使用 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)
比方说,我有一个 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)