我想到以下是更好的风格X-macro trick:
#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 标准中描述了宏等函数的预处理:§6.10.3 宏替换。相关部分如下:
¶10...后面跟着类似函数的宏名称的每个后续实例
由一个(
作为下一个预处理标记引入的序列
预处理标记,该标记被替换列表中的替换
定义(宏的调用)......
6.10.3.1 参数替换
¶1在调用类函数宏的参数之后
已经确定,参数替换就发生了。一个参数
在替换列表中,除非前面有 # 或 ## 预处理
标记或后跟 ## 预处理标记(见下文)将被替换
在其中包含的所有宏都具有相应的参数之后
已扩大。在被替换之前,每个参数的预处理
标记完全被宏替换,就好像它们构成了其余部分一样
预处理文件;没有其他可用的预处理标记。
6.10.3.4 重新扫描和进一步更换
¶1替换列表中的所有参数都被替换后
并且 # 和 ## 处理已发生,所有地标预处理
令牌被删除。得到的预处理标记序列是
重新扫描,以及所有后续的预处理标记
源文件,用于替换更多宏名称。
除了节名称和编号之外,C++ 标准中也存在相同的措辞。
所以当你插上电源时X_LIST
中,预处理器将替换X
尝试扩展后通过它X_LIST
就好像它是一个像宏一样的对象。既然不是,则留下的标记为X
is X_LIST
.
然后预处理器再次扫描该行。这次X_LIST
随后将是(
,因此将被扩展now.
将像宏名称这样的函数传递给“高阶函数”并非闻所未闻。这Boost.预处理器图书馆大量使用这个惯用语。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)