【问题标题】:Is it legal to pass the macro name to an X-Macro list将宏名称传递给 X-Macro 列表是否合法
【发布时间】:2019-11-26 23:47:25
【问题描述】:

我突然想到,以下是X-macro技巧的一种更可取的风格:

#define LIST_OF_COLOURS(X) \
    X(RED) \
    X(GREEN) \
    X(BLUE)

#define LIST_OF_FRUIT(X) \
    X(APPLE) \
    X(ORANGE) \
    X(TOMATO)

具体来说,将X 宏传递给列表,而不是在每次实例化列表时取消定义并重新定义它。这允许:

#define X_LIST(x) x,
#define X_STRING_LIST(x) #x,
#define COMPREHENSIVE_SETUP(n, l)  \
    enum n { l(X_LIST) };  \
    char const* n##Names[] = { l(X_STRING_LIST) };

COMPREHENSIVE_SETUP(Colour, LIST_OF_COLOURS)
COMPREHENSIVE_SETUP(Fruit, LIST_OF_FRUIT)

但问题是我不经常在野外看到这个成语,而且它不是维基百科所描述的,尽管每当我尝试它并且感觉更方便时它“似乎有效”。

我的问题是,这实际上是合法且完全定义的,还是我依赖​​未定义的行为?

【问题讨论】:

标签: c++ c c-preprocessor x-macros


【解决方案1】:

是的,它是有效的。 §6.10.3 宏替换在 C 标准中描述了类似宏的函数的预处理。相关部分如下:

¶10 ...随后的每个类似函数的宏名称的实例 由( 作为下一个预处理标记引入序列 预处理被替换列表替换的令牌 定义(宏的调用)....

6.10.3.1 参数替换

¶1 在调用类函数宏的参数之后 已被识别,参数替换发生。一个参数 在替换列表中,除非前面有 # 或 ## 预处理 令牌或后跟 ## 预处理令牌(见下文),被替换 在其中包含的所有宏都具有相应的参数之后 被扩大。在被替换之前,每个参数的预处理 标记被完全宏替换,就好像它们形成了其余的 预处理文件;没有其他可用的预处理令牌。

6.10.3.4 重新扫描和进一步替换

¶1替换列表中的所有参数都被替换后 和 # 和 ## 处理已经发生,所有 placemarker 预处理 令牌被删除。然后得到的预处理令牌序列是 重新扫描,以及所有后续的预处理标记 源文件,用于替换更多宏名称。

除了部分名称和编号之外,C++ 标准中也存在相同的措辞。

因此,当您插入X_LIST 时,预处理器将在尝试扩展X_LIST 之后将X 替换为它,就好像它是一个类似宏的对象一样。因为不是,X 留下的标记是X_LIST

然后预处理器再次扫描该行。这次X_LIST 后面会跟着一个(,因此现在会被扩展。

将像宏名称这样的函数传递给“高阶函数”并非闻所未闻。 Boost.Preprocessor 库大量使用了这个习语。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-12
    • 2019-02-12
    • 2022-08-20
    • 1970-01-01
    • 2015-08-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多