带 Boost.Preprocessor 的 X 宏?

发布于 2024-10-09 16:12:05 字数 258 浏览 7 评论 0原文

将其与我关于附加到 CPP 宏的问题分开:

有没有人这里使用 Boost.Preprocessor 库的数据类型来实现类似 X 宏的东西?

Splitting this off from my question regarding appending to CPP macros:

Has anyone here used the Boost.Preprocessor library’s data types to implement something like the X-macro?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

两相知 2024-10-16 16:12:05

我只是查了一下 X-Macro 应该是什么,我想我做了类似你要求的事情。

我想做的是轻松快速地支持一系列相当相似的类的序列化。我遇到的问题是我必须将一些运行时信息(int)转换为编译时类型(类)才能进行序列化。我本可以编写几个 case 语句来完成这项工作,但这意味着每次我想添加一个类时都必须更新几个函数。

为了解决这个问题,我首先定义了一个序列的a>:

#define WIN_MESSAGE_TYPE_SEQ \
    ((EM_REPLACESEL, em_replacesel))((WM_CHAR, wm_char)) //...

包含映射的元 大写名称是保存 int 的定义,小写名称是我在其他地方定义的类。

然后,我可以将此序列与一些 Boost 结合使用预处理器 为我生成各种代码。例如,要获得类的前向声明,我可以这样做:

#define WIN_MESSAGE_TYPE_BUILD_MACRO(r, _data_, _elem_) \
    class BOOST_PP_TUPLE_ELEM(2,1,_elem_);

BOOST_PP_SEQ_FOR_EACH(WIN_MESSAGE_TYPE_BUILD_MACRO, BOOST_PP_NIL, WIN_MESSAGE_TYPE_SEQ)

#undef WIN_MESSAGE_TYPE_BUILD_MACRO

为了执行运行时编译时间映射,我生成一系列如下的 case 语句:

#define WIN_MESSAGE_TYPE_BUILD_MACRO(r, _data_, _elem_) \
    case BOOST_PP_TUPLE_ELEM(2,0,_elem_): return win_message_serializer<BOOST_PP_TUPLE_ELEM(2,1,_elem_)>::serialize(msg, o_arch);

template <typename Archive>
void serialize_win_message (p_win_message_base msg, Archive& o_arch) {
    message_type_t message_type = msg->type();

    switch (message_type) {

    // This will generate a series of case statement for each message type that will invoke
    // the serializer for the correct types.
    BOOST_PP_SEQ_FOR_EACH(WIN_MESSAGE_TYPE_BUILD_MACRO, BOOST_PP_NIL, WIN_MESSAGE_TYPE_SEQ)

    default: //...
    };
}

#undef WIN_MESSAGE_TYPE_BUILD_MACRO

整个代码涉及的内容比这多得多,但这仍然应该让您了解如何使用 Boost 预处理器生成代码。在我的示例中,我只需更新序列即可快速轻松地为类添加序列化支持。

请注意,使用 Boost 预处理器不会生成非常可读的代码,因此我尝试使 for 每个宏使用的宏尽可能简单。如果有人对这个问题有更优雅的解决方案,我也不会感到惊讶。这正是我为个人项目想到的,我不介意额外的复杂性。

I just looked up what an X-Macro is supposed to be and I think I did something like what you're asking for.

What I wanted to do is to easily and quickly support serialisation for a series of fairly similar classes. The problem I had is that I had to convert some runtime information (an int) into a compile time type (a class) to be able to do my serialisation. I could have written a couple of case statements to do the job but that would mean that I have to update several functions each time I wanted to add a class.

To get around this problem, I first defined a sequence of tuples containing the mapping:

#define WIN_MESSAGE_TYPE_SEQ \
    ((EM_REPLACESEL, em_replacesel))((WM_CHAR, wm_char)) //...

The upper case names are defines that hold an int and the lower case names are classes that I defined somewhere else.

I can then use this sequence in conjunction with some of the Boost preprocessors to generate all sorts of code for me. For example, to get a forward declaration of the classes I can just do this:

#define WIN_MESSAGE_TYPE_BUILD_MACRO(r, _data_, _elem_) \
    class BOOST_PP_TUPLE_ELEM(2,1,_elem_);

BOOST_PP_SEQ_FOR_EACH(WIN_MESSAGE_TYPE_BUILD_MACRO, BOOST_PP_NIL, WIN_MESSAGE_TYPE_SEQ)

#undef WIN_MESSAGE_TYPE_BUILD_MACRO

To do the runtime to compile time mapping, I generate a series of case statements like this:

#define WIN_MESSAGE_TYPE_BUILD_MACRO(r, _data_, _elem_) \
    case BOOST_PP_TUPLE_ELEM(2,0,_elem_): return win_message_serializer<BOOST_PP_TUPLE_ELEM(2,1,_elem_)>::serialize(msg, o_arch);

template <typename Archive>
void serialize_win_message (p_win_message_base msg, Archive& o_arch) {
    message_type_t message_type = msg->type();

    switch (message_type) {

    // This will generate a series of case statement for each message type that will invoke
    // the serializer for the correct types.
    BOOST_PP_SEQ_FOR_EACH(WIN_MESSAGE_TYPE_BUILD_MACRO, BOOST_PP_NIL, WIN_MESSAGE_TYPE_SEQ)

    default: //...
    };
}

#undef WIN_MESSAGE_TYPE_BUILD_MACRO

The whole code involves quite a bit more than this but this should still give you an idea on how to generate code using the Boost preprocessors. In my example I can quickly and easily add serialisation support for a class by simply updating my sequence.

Note that using the Boost preprocessor doesn't produce very readable code so I try to keep the macro used by the for each macro as simple as possible. Also I wouldn't be surprised if someone somewhere has a more elegant solution to this problem. This is just what I came up with for a personal project where I don't mind the extra complexity.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文