使用 switch case 设置和获取成员变量的 C++ 元编程

C++ metaprograming to set and get member variables using switch case

比方说,我有一个 class,它可以有很多变量。这些变量中的每一个都将有一个唯一的枚举映射到它。我想使用 switch case 将 set/get 值赋给变量。我不想每次都为每个变量编写 "case",而是希望拥有扩展为 set/get 函数和相应开关盒的宏。

class myClass
{
  int m_i, m_j;
  void Set(int variable, int i);
  void Get(var variable, int& i);
};

enum var{ VAR_I, VAR_J };

//..........cpp.........
//here I will map enum to member variables
//so if i write this.
//
VARIABLE_START(myClass)
  VARIABLE(VAR_I, m_i)
  VARIABLE(VAR_J, m_j)
VARIABLE_END

//it should expand to....
void myClass::Set(var variable, int i)
{
   switch(var)
   {
      case VAR_I: ....
          break;
      case VAR_J: ....
          break;
  }
}

void myClass::Get(var variable, int& i)
{
   switch(var)
   {
      case VAR_I: ....
          break;
      case VAR_J: ....
          break;
  }
}

现在我在定义这些宏时遇到问题,这些宏应该扩展为两个(或更多)成员函数,每个成员变量都有 switch case。 任何形式的帮助表示赞赏。

对于预处理器方法,考虑使用 X-Macros:

#define APPLY_MY_VARIABLES \
    MY_VARIABLES(m_i, VAR_I) \
    MY_VARIABLES(m_j, VAR_J)
enum var {
#define MY_VARIABLES(VAR, ENUM) ENUM ,
    APPLY_MY_VARIABLES
#undef  MY_VARIABLES
    // NOTE: The above emits a trailing comma; that's allowed.
    // You may also add another enumerator you can use as a count.
};

class myClass
{
#define MY_VARIABLES(VAR, ENUM) int VAR;
    APPLY_MY_VARIABLES
#undef  MY_VARIABLES
   void Set(var variable, int i);
   void Get(var variable, int& i);
};

void myClass::Set(var variable, int i)
{
   switch(var)
   {
   default: ...
#define MY_VARIABLES(VAR,ENUM) \
      case ENUM: \
          VAR = i; \
          break;
      APPLY_MY_VARIABLES
#undef  MY_VARIABLES
  }
}
void myClass::Get(var variable, int& i)
{
   switch(var)
   {
      default: ...
#define MY_VARIABLES(VAR, ENUM) \
      case ENUM: \
          i = VAR; \
          break;
      APPLY_MY_VARIABLES
#undef  MY_VARIABLES
  }
}

要点是您创建了一个 "relation" 标记——一种用您想要的数据实例化对宏的多次调用的方法,但是您没有定义这些宏。在这里,关联是用一个主宏——应用宏创建的。

在使用时,您可以定义要扩展的宏以用于某些特定目的,然后使用主宏来应用关系本身。展开后,您应该立即取消定义内部宏(就像您要关闭 for 循环一样)。

另一种方法是通过将内部宏放在单独的文件中来建立关联:

foo.def

MY_VARIABLES(m_i, VAR_I)
MY_VARIABLES(m_j, VAR_J)

此文件便成为关系。在这种情况下应用是通过包含文件来完成的:

class myClass
{
#define MY_VARIABLES(VAR, ENUM) int VAR;
#include "foo.def"
#undef  MY_VARIABLES
   void Set(var variable, int i);
   void Get(var variable, int& i);
};

这是@NickyC 暗示的那种无宏解决方案的草图 在:

// myClass,h
#include <map>

enum var{ VAR_I, VAR_J };

struct myClass
{
    int m_i, m_j;
    void Set(var variable, int i) {
        (this->*map[variable]) = i;
    }
    void Get(var variable, int& i) const {
        i = (this->*map[variable]);
    }
private:
    static std::map<var,int myClass::*> map;
};

// myClass.cpp
std::map<var,int myClass::*> myClass::map = {
    { VAR_I, &myClass::m_i },
    { VAR_J, &myClass::m_j }
};

它依赖于将 var 值映射到 myClass 的成员。去测试, 追加:

#include <iostream>

using namespace std;

int main()
{
    myClass mc;
    mc.Set(VAR_I,2);
    mc.Set(VAR_J,4);
    int i, j;
    mc.Get(VAR_I,i);
    mc.Get(VAR_J,j);
    cout << i << '\n' << j << endl;
    return 0;
}

输出:

2
4

顺便提一下:

    void Get(var variable, int& i) const {
        i = (this->*map[variable]);
        // or whatever
    }

很可能不如:

方便
    int const & Get(var variable) const {
        return (this->*map[variable]);
        // or whatever
    }

(gcc 4.9.2, -std=c++11)