convert string/character to class member/method in c++

这一生的挚爱 提交于 2021-01-27 14:50:16

问题


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.


回答1:


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!




回答2:


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).




回答3:


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;
}



回答4:


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.



来源:https://stackoverflow.com/questions/19557881/convert-string-character-to-class-member-method-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!