有人可以解释为什么会有效:
#include <iostream>
using namespace std;
#define cat(a,b) cat_1(a,b)
#define cat_1(a,b) a ## b
int main()
{
cat(c,cat(o,cat(u,t))) << "Hello world!";
return 0;
}
但是具有一个较少级别的宏间接的相同代码不会:
#include <iostream>
using namespace std;
#define cat(a,b) a ## b
int main()
{
cat(c,cat(o,cat(u,t))) << "Hello world!";
return 0;
}
我看过这个:
http://www.boost.org/doc/libs/1_55_0/libs/preprocessor/doc/
虽然它说明了问题但我仍然不明白这是如何解决它的。当我在这个(g ++ -E)上运行预处理器时:
#include <iostream>
using namespace std;
#define cat(a,b) cat_1(a,b)
int main()
{
cat(c,cat(o,cat(u,t))) << "Hello world!";
return 0;
}
它将该行扩展为:
cat_1(c,cat_1(o,cat_1(u,t))) << "Hello world!"
所以看起来问题应该仍然存在,因为它直接映射到只有'cat'的行
答案 0 :(得分:4)
##
运算符。外部调用首先扩展为ccat(o,cat(u,t))
,然后扩展到ccat(o, ut)
并停在那里。
额外间接允许在令牌粘贴之前重新扫描。
答案 1 :(得分:0)
简短回答:宏定义中存在##运算符会停止正常级联替换它附近的宏参数。
获取第一个(工作)版本的子集:
#define cat(a,b) cat_1(a,b)
#define cat_1(a,b) a ## b
cat(o,cat(u,t))
最后一行是标记化的:
cat ( o , cat ( u , t ) )
cat和(标记表示调用cat()宏的开始,因此预处理器开始用cat()的定义替换它:
cat_1(
此时它必须替换&#34; a&#34;传入的参数(即&#34; o&#34;),所以它继续:
cat_1(o,
现在必须更换参数&#34; b&#34;传入的参数(即&#34; cat(u,t))&#34;),但这个参数本身就是一个宏调用,因此在替换为&#34; cat_1(u,t)之前会被扩展)&#34;然后到&#34;你## t&#34;最后到了&#34; ut&#34;,所以,回到顶层,我们最终得到:
cat_1(o,ut)
这是重新扫描,变成:
o ## ut
最后到
出
正如所料。
在非工作的情况下,##附近的非扩展规则发挥作用:
#define cat(a,b) a ## b
cat(o,cat(u,t))
这次预处理器开始替换外部cat()调用时,会立即遇到参数&#34; a&#34;并且必须用传递的参数&#34; o&#34;替换它,这很好,后跟##:
o ##
现在进入&#34; b&#34;它必须用参数替换&#34; cat(u,t)&#34;。 然而,与上面的工作示例不同,这次,参数不会递归扩展,因为根据C标准,紧接在##运算符之前或之后的参数不得递归展开。所以,它只是离开了猫(你,t)&#34;因为它得到它并最终得到:
o ## cat(u,t)
然后折叠成
ocat(u,t)
这是预处理器停止的地方,因为它不知道&#34; ocat&#34;。
停止递归参数扩展的##(和#)预处理器操作符在C标准的6.10.3.1节中列出。