将宏名称传递给 X-Macro 列表是否合法

Is it legal to pass the macro name to an X-Macro list

我想到以下是 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)

但问题是我不经常在野外看到那个成语,而且它不是维基百科描述的,尽管它 "seems to work" 每当我尝试它并且感觉更方便时。

我的问题是,这是否真的合法且已完全定义,还是我依赖​​于未定义的行为?

是的,有效。 Pre-processing 类似宏的函数在 C 标准中由 §6.10.3 宏替换 描述。相关部分如下:

¶10 ...Each subsequent instance of the function-like macro name followed by a ( as the next preprocessing token introduces the sequence of preprocessing tokens that is replaced by the replacement list in the definition (an invocation of the macro)....

6.10.3.1 Argument substitution

¶1 After the arguments for the invocation of a function-like macro have been identified, argument substitution takes place. A parameter in the replacement list, unless preceded by a # or ## preprocessing token or followed by a ## preprocessing token (see below), is replaced by the corresponding argument after all macros contained therein have been expanded. Before being substituted, each argument's preprocessing tokens are completely macro replaced as if they formed the rest of the preprocessing file; no other preprocessing tokens are available.

6.10.3.4 Rescanning and further replacement

¶1 After all parameters in the replacement list have been substituted and # and ## processing has taken place, all placemarker preprocessing tokens are removed. The resulting preprocessing token sequence is then rescanned, along with all subsequent preprocessing tokens of the source file, for more macro names to replace.

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

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

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

将像宏名称这样的函数传递给 "higher order function" 并非闻所未闻。 Boost.Preprocessor 库大量使用了这个习语。