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

时间:2015-03-27 03:55:20

标签: c++ c-preprocessor metaprogramming

让我们说,我有一个类,它可以有很多变量。每个变量都有一个映射到它的唯一枚举。我想使用switch case为变量设置/获取值。而不是每次写作" case"对于每个变量,我想要宏扩展到set / get函数和相应的switch case。

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。 任何形式的帮助表示赞赏。

2 个答案:

答案 0 :(得分:1)

对于预处理器方法,请考虑使用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
  }
}

重点在于您创建了令牌的“关系” - 一种使用您想要的数据实例化对宏的多次调用的方法,但是您将这些宏保留为未定义。在这里,使用主宏创建关联 - 应用宏。

在使用时,您可以定义宏以扩展您想要的特定用途,然后使用主宏来应用关系本身。在扩展之后,您应该立即取消定义内部宏(就像关闭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);
};

答案 1 :(得分:1)

这是@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)