有没有办法使用宏在编译时从其他地方向枚举添加附加值?

发布于 2024-07-30 09:36:01 字数 175 浏览 4 评论 0原文

我们使用一个大枚举来传递消息,并且我们的代码库中有一些可选部分使用特定的消息,如果要编译这些部分,实际上只需要将其添加到枚举中。有没有一种方法可以定义一个宏,它可以做这个或类似的事情? 我希望能够仅添加 REGISTER_MSG(MESSAGE_NAME); 到可选代码中文件的开头。 我想真正的问题是宏只替换它们编写位置的代码。

We use one big enum for message passing and there are optional parts of our code base that use specific messages that really only need to be added to the enum if those parts are to be compiled in. Is there a way to define a macro that could do this or something similar? I would like to be able to just add REGISTER_MSG(MESSAGE_NAME); to the beginning of a file in the optional code. I guess the real problem is that macros only replace the code at the location they are written.

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

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

发布评论

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

评论(5

芯好空 2024-08-06 09:36:01

事实上,您不能让宏修改其他编译单元中的代码。 所有编译单元的枚举应该相同。

(顺便说一句,我可能不会使用带有自动分配值的枚举来识别协议中的消息。)

Indeed, you can't have macros modifying code in other compilation units. And the enum should be the same for all the compilation units.

(I wouldn't probably use enum with automatically assigned value for identifying messages in a protocol, BTW.)

浴红衣 2024-08-06 09:36:01

我会重新考虑这个设计,但如果你真的想这样做,你可以使用 Make 在编译时构造枚举头。

BigEnum.h:
    # First put in everything up to the opening brace,
    cat BigEnumTop > $@ 
    # then extract all of the message names and add them (with comma) to BigEnum.h,
    cat $(OPTIONAL_SOURCES) | grep REGISTER_MSG | sed 's/.*(\(.*\))/\1/' >> $@
    # then put in the non-optional message names, closing brace, and so on.
    cat BigEnumBottom >> $@

I would rethink this design, but if you really want to do it this way you can construct the enum header at compile time using Make.

BigEnum.h:
    # First put in everything up to the opening brace,
    cat BigEnumTop > $@ 
    # then extract all of the message names and add them (with comma) to BigEnum.h,
    cat $(OPTIONAL_SOURCES) | grep REGISTER_MSG | sed 's/.*(\(.*\))/\1/' >> $@
    # then put in the non-optional message names, closing brace, and so on.
    cat BigEnumBottom >> $@
空心↖ 2024-08-06 09:36:01

您可以使用一些丑陋模板黑客来执行类似的操作:

#define REGISTER_MSG(MESSAGE_NAME) \
  struct tag_##MESSAGE_NAME { }; \
  static const int &MESSAGE_NAME = assign_message_id<tag_##MESSAGE_NAME>::value;

template<typename Tag>
struct assign_message_id {
    static const int value;
};

// should be compiled only once; don't put the definition in a header
int next_message_id() {
    static int id = 0;
    return id++;
}

template<typename Tag>
const int assign_message_id<Tag>::value = next_message_id();

但是,由于这些不是恒定的,因此它们不能在switch中使用。 此外,它们可以从一个编译更改为另一个编译,甚至可以从一次运行更改为下一次运行。

另一种选择是编写一个脚本来扫描整个代码库中的这些 REGISTER_MSG 标记,并根据它们发出标头。 那么你只需要:

#define REGISTER_MSG(MESSAGE_NAME) /* no-op */

You could do something like this with some ugly template hacks:

#define REGISTER_MSG(MESSAGE_NAME) \
  struct tag_##MESSAGE_NAME { }; \
  static const int &MESSAGE_NAME = assign_message_id<tag_##MESSAGE_NAME>::value;

template<typename Tag>
struct assign_message_id {
    static const int value;
};

// should be compiled only once; don't put the definition in a header
int next_message_id() {
    static int id = 0;
    return id++;
}

template<typename Tag>
const int assign_message_id<Tag>::value = next_message_id();

However, since these are not constant, they could not be used in a switch. Additionally, they could change from compile to compile - or even from one run to the next.

Another option would be to write a script to just scan your entire codebase for these REGISTER_MSG tags, and emit a header based on them. Then you'd just need:

#define REGISTER_MSG(MESSAGE_NAME) /* no-op */
羁〃客ぐ 2024-08-06 09:36:01

简单的。 将 #include 放入枚举中,并调整包含路径,以便包含适当的文件。

enum myenum
{
   x,
   y,
#include "enum_extender.h"
}

Easy. Put a #include in the enum, and tweak the include paths so that the appropriate file is included.

enum myenum
{
   x,
   y,
#include "enum_extender.h"
}
凉宸 2024-08-06 09:36:01

Makefile 解决方案的变体:

# BigEnum.h #includes BigEnum.inc
BigEnum.h: BigEnum.inc
BigEnum.inc:
    # Extract all of the message names for inclusion (with comma) in BigEnum.h
    cat $(OPTIONAL_SOURCES) | grep REGISTER_MSG | sed 's/.*(\(.*\))/\1/' >> $@

优点是支持工具将看到一个合理的 BigEnum.h,其中至少包含一些枚举值,并且源代码存储库将包含单个文件,而不是单独的页眉和页脚。

显然,您需要在整个代码中使用 BigEnum 的单一定义,否则可能会违反 ODR。 另请考虑如果您的“可选”值恰好是枚举中的第 256 个或第 65536 个,会发生什么情况。

Variant of the Makefile solution:

# BigEnum.h #includes BigEnum.inc
BigEnum.h: BigEnum.inc
BigEnum.inc:
    # Extract all of the message names for inclusion (with comma) in BigEnum.h
    cat $(OPTIONAL_SOURCES) | grep REGISTER_MSG | sed 's/.*(\(.*\))/\1/' >> $@

The advantages are that support tooling will see a reasonable BigEnum.h with at least some enum values, and the source code repository will contain a single file instead of a seperate header and footer.

You obviously need to have a single definition of BigEnum throughout your code, or else you might violate the ODR. Also consider what happens if your "optional" value happens to be the 256th or 65536th in an enum.

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