C++ 11嵌套宏调用?

And*_*zos 15 c c++ macros c++11

它在C++ std 16.3.4中说:

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

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

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

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

什么是嵌套的宏替换?

具体考虑:

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

g(f)(g)(3)
Run Code Online (Sandbox Code Playgroud)

我原以为是:

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
Run Code Online (Sandbox Code Playgroud)

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

2 1 2 3
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?

更新:

经过大量研究,让我用一个更简单的例子来澄清这个问题:

#define A(x) B
#define B(x) A(x)

A(i)(j)
Run Code Online (Sandbox Code Playgroud)

这扩展如下:

A(i)(j)
B(j)
A(j)
Run Code Online (Sandbox Code Playgroud)

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

M-o*_*-se 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)
Run Code Online (Sandbox Code Playgroud)

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

[剪断]

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

G0(42)
NIL(G_1)(42)
G_1(42)
NIL(42)
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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