Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I access a struct property by string name?

Tags:

c++

c++11

vector

I have a struct:

typedef struct Tick {
    double open;
    double high;
    double low;
    double close;
    double ema100;
} Tick;

I would like to access a property given a key:

Tick currentTick = {44.5, 45.1, 44.2, 44.6, 44.255};
std::string key = "ema100";

std::cout << currentTick[key];

Is there a way to do this without using std::map? I imagine the answer is no, but I just want to be certain before modifying everything to use std::map and increase my memory requirements.

like image 247
Chad Johnson Avatar asked Apr 08 '16 18:04

Chad Johnson


2 Answers

Is there a way to do this without using std::map?

As long as you are willing to live with a series of cascading if-else statements, you can do that.

I would question the design though.

You can get there partially using tag based member variables. Sample working example:

#include <iostream>

struct OpenTag {};
struct HighTag {};
struct LowTag {};
struct CloseTag {};
struct Ema100Tag {};

struct Tick {

   template <typename Tag> struct Member
   {
      double val;

      operator double () const { return val; }

      operator double& () { return val; }
   };

   struct AllMembers : Member<OpenTag>, 
                       Member<HighTag>,
                       Member<LowTag>,
                       Member<CloseTag>,
                       Member<Ema100Tag> {};

   AllMembers data;

   template <typename Tag>
      double operator[](Tag t) const
      {
         return (Member<Tag> const&)(data);
      }

   template <typename Tag>
      double& operator[](Tag t)
      {
         return (Member<Tag>&)(data);
      }

};

int main()
{
   Tick t;
   t[OpenTag()] = 12.345;
   std::cout << t[OpenTag()] << std::endl;
}

Output:

12.345
like image 141
R Sahu Avatar answered Sep 30 '22 05:09

R Sahu


The feature you're looking for is called reflection. This is not supported by native C++. You can either check for some 3rd-party libraries to do the reflection for you (but still would require lot of manual effort).

Or the other option is (as you mentioned) using std::map (or rather std::unordered_map as it would perform better) to map the name to id or offset (pointer) of the field within the class and then via switch statement (in former case) or directly using the pointer (in the latter case) modify the field value.

like image 24
Zbynek Vyskovsky - kvr000 Avatar answered Sep 30 '22 04:09

Zbynek Vyskovsky - kvr000