C ++ 11嵌套宏调用?

时间:2013-03-23 03:28:24

标签: c++ c c++11 macros

它在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都被视为符合要求。

3 个答案:

答案 0 :(得分:6)

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

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段:

     
    

[snipped]

  
     

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

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

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

     

J11委员会在本文中的初衷是结果应该是42,正如其作者Dave Prosser提供的替代算法的原始伪代码描述所证明的那样。 / strong>然而,英文描述省略了伪代码的一些细微之处,因此可以说这个案例的答案是错误的。

     

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

     

Notes(通过Tom Plum)从2004年4月WG14会议开始:

     

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

答案 1 :(得分:0)

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

#define g( x ) f( x )
#define f( x ) g( x )

g( 1 ) -- > f( 1 ) --> stop 

答案 2 :(得分:0)

因为它提及&#34;(不包括源文件的其余预处理令牌)。&#34; g的第一次替换仅见f。现在f有资格替换从文件其余部分获取的预处理令牌,但f生成g的程序记录无处可去。替换f(g)会产生g,同样不会被递归。

嵌套替换是由另一个替换替换的替换,而不是其替换来自另一个替换的替换。根据后一种定义,替代品可能有几个相互排斥的嵌套父母。