3

假设我想定义以下结构的类:

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 预处理器库,但如果你有一个使用它的好解决方案,请继续。但是,我非常喜欢一个简单的解决方案,如果有的话。

4

1 回答 1

1

这是一个示例,它实际上并没有构建一个结构来缓存映射中的值,而是简单地在构造函数中检查映射是否包含字段,正如在开头问题的评论中所讨论的那样。

#define DEF_CLASS(CLASSNAME) \
    struct CLASSNAME { \
    CLASSNAME(QVariantMap& map) {\
    _DEF_CLASS_TAIL/*..."curry the arguments"...*/
#define _DEF_CLASS_TAIL(FIELDS) \
        FIELDS \
    }};
#define CHK_FIELD(TYPE, NAME) \
    if (typeid(TYPE)!=typeid(map[#NAME])) \
    { throw std::runtime_error(#NAME" missing or wrong type");}
DEF_CLASS(MyClass)(
    CHK_FIELD(int, x)
    CHK_FIELD(bool, y)
    CHK_FIELD(float, z)
);

这会从预处理器中生成以下内容(在运行 astyle 之后):

struct MyClass {
   MyClass(QVariantMap& map) {
      if (typeid(int) != typeid(map["x"])) {
         throw std::runtime_error("x"" missing or wrong type");
      }
      if (typeid(bool) != typeid(map["y"])) {
         throw std::runtime_error("y"" missing or wrong type");
      }
      if (typeid(float) != typeid(map["z"])) {
         throw std::runtime_error("z"" missing or wrong type");
      }
   }
};

编辑:我不是 100% 确定 typeid 比较会像这样工作,但应该直接用有效的检查替换它。

于 2013-05-08T23:29:53.743 回答