Question

Is there a way to convert string or characters to class member/member functions to access them dynamically?

for ex. this particular code,

 #include <iostream>
 #include <map>

 using namespace std;

 class agnt {
 public:
 int x, y;
 agnt(int a=0, int b=0) : x(a), y(b) {}
 };


 int main() {
      map<int,agnt> agntID;
      agnt temp;
      temp.x=1;
      temp.y=5;

      agntID[1]=temp;

      for(char tmp='x'; tmp<'z'; tmp++) {
         cout<<agntID[1].tmp<<'\n';     //Here I get the following error: tmp is
         }                              //not a member of class agnt
 }

Is there a way to convert the character 'tmp' such that it is identified as a class member? Any tips or solution will be appreciated.

Was it helpful?

Solution 2

You can't do this in C++ because it's a statically-typed language. One way to get this sort of behaviour is to provide accessing wrappers:

template <char c>
struct getter {
};


template <>
struct getter<'x'> { 
   static int get(const agnt &theAgnt) {
      return theAgnt.x;
   }
};


template <>
struct getter<'y'> { 
   static int get(const agnt &theAgnt) {
      return theAgnt.y;
   }
};

template <char c>
int get(const agnt &theAgnt) {
    return getter<c>::get(theAgnt);
}

And call like:

agnt temp;
//... set members
std::cout << get<'x'>(temp) << std::endl;

However, the for loop won't work the way you expect, because the template parameters need to be determined at compile time. Also, you can't just request any old thing, unless you define a get function in the unspecialised getter which returns some sort of NULL-indicator, like INT_MIN.

However, this is all really a hack to get something vaguely similar to a dynamic language. But it's not really anything different from just referencing temp.x. Instead, you should try to adhere to C++ conventions and enjoy the static typing!

OTHER TIPS

C++ doesn't have any introspection so no it's not possible.

However, you can "hack" it by having another std::map that contains the names as keys, and the value is a reference to the variable:

agnt temp;

std::unordered_map<char, int&> variable_map = {
    { 'x', temp.x },
    { 'y', temp.y }
};

variable_map['x'] = 123;
std::cout << variable_map['y'] << '\n';

It's generally not worth it though, as it more work. Especially if you want to do this for multiple variables (as each structure variable needs its own mapping).

No

C++ has no introspection and reflection abilities. You must code that kind of dynamic access yourself.

A reasonable alternative to hand-coding can in some cases to use an external schema file to describe your C++ classes and then generate automatically the classes and the introspection and reflection code. You cannot do that using templates because even metaprogramming abilities of C++ are totally absent in this area.

Generating code by directly parsing .h in general can be much more difficult because of how complex the C++ syntax is (it took quite a few years even for compiler makers to agree to a decent extent about what is valid C++ code and what is not).

You can use templates to simplify the publishing, but still doing it manually:

template<typename T, typename C>
std::map<std::string, T C::*>& attribute_map() {
    static std::map<std::string, T C::*> m;
    return m;
}

template<typename C>
struct Published {
    template<typename T>
    T& attribute(const std::string& name) {
        std::map<std::string, T C::*>& m = attribute_map<T, C>();
        typename std::map<std::string, T C::*>::const_iterator i=m.find(name);
        if (i == m.end()) {
            throw std::runtime_error("Attribute not present");
        } else {
            return static_cast<C *>(this)->*i->second;
        }
    }
};

For each attribute you will need to explicit "publish" it

template<typename T, typename C>
void publish(const std::string& name, T C::*mp) {
    attribute_map<T, C>()[name] = mp;
}

Given the above boilerplate code you can then create a class and publish some of its members by deriving from Published<Class>:

struct MyClass : Published<MyClass> {
    int a;
    double b;
    std::string c;

    MyClass(int a, double b, const std::string& c)
        : a(a), b(b), c(c)
    {
    }
};

Then you will need to call the publish function just once at the start of the program to be able to dynamically access attributes:

int main(int argc, const char *argv[]) {
    publish("a", &MyClass::a);
    publish("b", &MyClass::b);
    publish("c", &MyClass::c);

    MyClass m1(3, 4.5, "This is a test");
    MyClass m2(6, 7.8, "This is another test");

    std::cout << m1.attribute<int>("a") << "\n";
    std::cout << m2.attribute<std::string>("c") << "\n";
    return 0;
}

Whilst everyone who has answered NO is correct.... That doesn't tell the whole story. There is nothing in the language to allow you to do that, however that doesn't mean that the environment wont allow it.

For instance, on vxworks, you can call symFindByName() to look up a function, variable or any other symbol, and you can then call the function through the pointer it provides. But this relies on the OS API, and is probably a side effect of the way the vxworks linker works

Other OS might have similar features.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top