假设我想定义以下结构的类:
struct MyClass {
int x;
bool y;
float z;
MyClass(QVariantMap data) : x(data["x"]), y(data["y"]), z(data["z"]) {}
};
如您所见,我有一个 QVariantMap (类似于std::map<std::string, boost::variant<...>>
那些不熟悉 Qt 的人),我希望能够在不进一步了解其字段的情况下构造这样的类型,因此方便的构造函数应该“反序列化" 地图上的字段。
我需要几个这种风格的类,并且我希望定义尽可能干净,以实现最大的可维护性(关于字符串键中的拼写错误)、可读性和自动化。
我想到了一个如下的宏观结构:
DEF_CLASS(MyClass)(
DEF_FIELD(int, x)
DEF_FIELD(bool, y)
DEF_FIELD(float, z)
);
当我只想生成字段而不是构造函数时,我没有看到任何问题(其他方式也是可能的,但我将只演示前者):
#define DEF_CLASS(CLASSNAME) \
struct CLASSNAME { \
_DEF_CLASS_TAIL/*..."curry the arguments"...*/
#define _DEF_CLASS_TAIL(FIELDS) \
FIELDS \
}
#define DEF_FIELD(TYPE, NAME) TYPE NAME;
我定义了启动类定义的第一个宏,并使用“curry”技术将第二个括号转发到第二个宏,该宏放置类定义的内容 ( FIELDS
),然后将其关闭。这样——我的想法也是如此——我可以访问FIELDS
第二个宏中的 。
但是我现在如何输出两次字段,一次定义实际字段,一次输出成员初始化?
我知道,如果我DEF_CLASS_FIELD
以两种不同的方式定义宏,然后在上面的定义代码中“包含”字段,每个宏定义一个字段,我可以正确地一个接一个地打印它们。但是由于字段列表是(并且应该)在类定义中,我不能简单地包含两次。
还有其他选择吗?
我尽量避免使用 Boost 预处理器库,但如果你有一个使用它的好解决方案,请继续。但是,我非常喜欢一个简单的解决方案,如果有的话。