C ++ 11嵌套宏调用?

它在C ++ std 16.3.4中说:

重新扫描生成的预处理标记序列[来自宏调用替换]以及源文件的所有后续预处理标记,以替换更多的宏名称。

如果在替换列表的扫描期间(不包括源文件的其余预处理标记)找到要替换的宏的名称,则不会替换它。

此外,如果任何嵌套替换遇到要替换的宏的名称,则不会替换它。

这些未替换的宏名称预处理令牌不再可用于进一步替换,即使它们稍后(重新)检查在其中否则将替换该宏名称预处理令牌的上下文中。

什么是嵌套宏替换?

具体考虑:

#define f(x) 1 x #define g(x) 2 x g(f)(g)(3) 

我原以为是:

 g(f)(g)(3) <-- first replacement of g, ok 2 f(g)(3) <-- nested replacement of f, ok 2 1 g(3) <-- second nested replacement of g, don't replace, stop 

然而gcc意外地继续进行第二次替换g,产生:

 2 1 2 3 

有任何想法吗?

更新:

经过大量研究后,让我通过一个更简单的例子来解决这个问题:

 #define A(x) B #define B(x) A(x) A(i)(j) 

这扩展如下:

 A(i)(j) B(j) A(j) 

该标准未规定是否应将A(j)扩展为B 委员会决定以这种方式离开,因为预计现实世界的程序不会依赖于这种行为,所以将A(j)未扩展并将A(j)扩展到B都被认为是符合要求的。

这解释了原始意图,以及为什么没有对该主题的标准添加澄清:

http://open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#268


268.重新扫描的替换文本中的宏名称抑制

:16.3.4 [cpp.rescan] 状态 :打开发布者 :Bjarne Stroustrup 日期 :2001年1月18日

从标准中不清楚以下示例的结果应该是什么:

 #define NIL(xxx) xxx #define G_0(arg) NIL(G_1)(arg) #define G_1(arg) NIL(arg) G_0(42) 

标准的相关文本见16.3.4 [cpp.rescan]第2段:

[剪断]

G0(42)的扩展顺序如下:

 G0(42) NIL(G_1)(42) G_1(42) NIL(42) 

问题是在该序列的最后一行中使用NIL是否符合所引用文本下的非替换。 如果是,结果将是NIL(42) 。 如果没有,结果将只是42

J11委员会在本文中的初衷是结果应该是42 ,正如其作者Dave Prosser提供的替换算法的原始伪代码描述所certificate的那样。 然而,英语描述省略了伪代码的一些细微之处,因此可以说对于这种情况给出了错误的答案。

建议的解决方案(Mike Miller) :[snipped]

2004年4月WG14会议记录(通过Tom Plum):

早在20世纪80年代,一些WG14人就明白,“非替代”措辞与制作伪代码的尝试之间存在细微差别。 该委员会的决定是,“野外”的实际计划不会冒险进入这一领域,并且试图减少不确定性并不值得改变实施或计划的一致性状态的风险。

g(x)总是被2 x代替。 在g的第二个嵌套替换中,用x=3调用g(x) ,因此产生结果2 3 。 我的理解是编译器不会用它的值替换宏,以防它产生无限循环:

 #define g( x ) f( x ) #define f( x ) g( x ) g( 1 ) -- > f( 1 ) --> stop 

因为它提到“(不包括源文件的其余预处理标记)。” 第一次替换g只能看到f 。 现在f有资格替换从文件其余部分获取的预处理标记,但是程序记录f是由g生成的。 f(g)的替换产生g ,其同样不受递归的影响。

嵌套替换是由另一个替换替换的替换,而不是其替换来自另一个替换的替换。 通过后一种定义,替换可以有几个互斥的嵌套父母。