【问题标题】:convert string/character to class member/method in c++将字符串/字符转换为 C++ 中的类成员/方法
【发布时间】:2013-10-24 05:45:13
【问题描述】:

有没有办法将字符串或字符转换为类成员/成员函数以动态访问它们?

例如。这个特定的代码,

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

有没有办法转换字符 'tmp' 使其被识别为类成员?任何提示或解决方案将不胜感激。

【问题讨论】:

    标签: c++ class class-members


    【解决方案1】:

    C++ 没有任何 introspection 所以不,这是不可能的。

    但是,您可以通过另一个 std::map 来“破解”它,其中包含名称作为键,值是对变量的引用:

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

    但通常不值得,因为它更有效。特别是如果您想对多个变量执行此操作(因为每个结构变量都需要自己的映射)。

    【讨论】:

      【解决方案2】:

      您不能在 C++ 中执行此操作,因为它是一种静态类型语言。获得这种行为的一种方法是提供访问包装器:

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

      然后像这样调用:

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

      但是,for 循环不会按您期望的方式工作,因为模板参数需要在编译时确定。此外,您不能只请求任何旧的东西,除非您在未专门化的getter 中定义一个get 函数,该函数返回某种NULL 指示符,例如INT_MIN

      然而,这一切都是为了获得类似于动态语言的东西模糊地。但这与仅引用 temp.x 并没有什么不同。相反,您应该尝试遵守 C++ 约定并享受静态类型!

      【讨论】:

        【解决方案3】:

        没有

        C++ 没有自省和反射能力。您必须自己编写这种动态访问的代码。

        在某些情况下,手动编码的合理替代方案可以使用外部模式文件来描述您的 C++ 类,然后自动生成类以及内省和反射代码。你不能使用模板来做到这一点,因为这个领域甚至完全没有 C++ 的元编程能力。

        一般来说,通过直接解析.h 来生成代码可能要困难得多,因为 C++ 语法非常复杂(即使是编译器制造商也花了好几年的时间才在相当程度上同意什么是有效的 C++ 代码和什么不是)。

        您可以使用模板来简化发布,但仍需手动操作:

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

        对于每个属性,您需要明确“发布”它

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

        鉴于上述样板代码,您可以创建一个类并通过从Published&lt;Class&gt; 派生来发布它的一些成员:

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

        然后您只需在程序开始时调用一次publish 函数即可动态访问属性:

        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】:

          虽然回答“否”的每个人都是正确的......但这并不能说明全部情况。 语言中没有任何内容允许您这样做,但这并不意味着环境不允许这样做。

          例如,在 vxworks 上,您可以调用 symFindByName() 来查找函数、变量或任何其他符号,然后您可以通过它提供的指针调用该函数。但这依赖于 OS API,并且可能是 vxworks 链接器工作方式的副作用

          其他操作系统可能有类似的功能。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-02-03
            • 1970-01-01
            • 2015-02-18
            相关资源
            最近更新 更多