sh1*_*sh1 4 c c++ c-preprocessor x-macros
在我看来,以下是X宏技巧的首选样式:
#define LIST_OF_COLOURS(X) \
X(RED) \
X(GREEN) \
X(BLUE)
#define LIST_OF_FRUIT(X) \
X(APPLE) \
X(ORANGE) \
X(TOMATO)
Run Code Online (Sandbox Code Playgroud)
具体来说,将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)
Run Code Online (Sandbox Code Playgroud)
但是问题是我没有经常在野外看到这种习语,这不是Wikipedia所描述的,即使我每次尝试并觉得更方便的时候它似乎都可以工作。
我的问题是,这实际上合法且已完全定义,还是我依赖未定义的行为?
是的,这是有效的。像宏这样的函数的预处理在C标准中由§6.10.3宏替换描述。相关部分如下:
¶10 ...每个类似函数的宏名称的后续实例,后跟一个
(作为下一个预处理标记,引入了一系列预处理标记,这些序列在定义中被替换列表替换(调用宏)。6.10.3.1参数替换
¶1确定了调用函数式宏的参数后,进行参数替换。除非包含在其中的所有宏都已扩展,否则替换列表中的参数(除非在#或##预处理令牌之前或在##预处理令牌之后(请参见下文))被相应的参数替换。在被替换之前,每个参数的预处理标记都被完全替换为宏,就好像它们构成了其余的预处理文件一样。没有其他预处理令牌可用。
6.10.3.4重新扫描并进一步更换
¶1在替换列表中的所有参数并执行#和##处理后,所有地标预处理令牌都将被删除。然后,重新扫描所得的预处理令牌序列以及源文件的所有后续预处理令牌,以替换更多的宏名称。
除了部分名称和编号外,C ++标准中也存在相同的措词。
因此,当您插入X_LIST时,preprcoessor将X在尝试扩展后替换为它,X_LIST就像它是一个像宏一样的对象。由于不是,所以for剩下的标记X是X_LIST。
然后预处理器再次扫描该行。这次X_LIST将跟随一个(,因此现在将被扩展。
将宏的名称之类的函数传递给“高阶函数”并非闻所未闻。该Boost.Preprocessor库大量使用了这个成语。
| 归档时间: |
|
| 查看次数: |
58 次 |
| 最近记录: |