这段代码在Visual Studio 2015中编译,但不在Clang中编译:
#define COMMA ,
#define MC(a) a
#define MA(a,b,c) MC(a b c)
map <MA(int,COMMA,int)> FF;
看来Clang在将 COMMA 宏提交给MC()宏之前会扩展它。根据C ++标准,“谁是对的”?另外,我怎样才能让Clang表现得像Visual Studio?
编辑:简化了示例,并更改了一些宏名称。
答案 0 :(得分:0)
Clang符合标准; Visual Studio没有。我认为让Clang不符合标准会有很多麻烦,所以我不会试图回答“我如何让Clang像Visual Studio一样行事?”。也许那不是你想知道的。
当编译器识别出类似函数宏的调用(即带参数的宏)时,它使用C ++标准的§16.3[cpp.replace]
中详细说明的过程扩展宏。在下文中,我通过不考虑#
和##
运算符简化了过程,因为它们没有出现在您的示例中,并且完整过程更复杂。
我们将检查调用MC(int, COMMA, int)
。这是在编译器看到令牌MC
和(
之后发生的事情,它表示调用宏。
编译器识别参数是什么,包括查找右括号。有三个参数,对应于参数的数量,所以没关系。参数尚未扩展,因此编译器只能在源文件中看到标点符号。它将参数标识为int
,COMMA
和int
。
每个参数(除了相应参数参与标记连接或字符串化的参数 - 但正如我所说,我不会在这里进入那个场景)然后完全展开。这在它们被替换到宏体之前发生,因此宏的参数的名称不会从宏中泄漏出来。所以现在这三个论点是int
,,
和int
。
制作宏体的副本,其中每个参数都用相应的(完全展开的)参数代替。宏观体(“替换列表”,标准符号)是MC(A B C)
;在替换参数后,变为MC(A , C)
。
将步骤3中创建的标记序列插入到输入中以代替宏调用,并继续预处理。
此时,编译器将看到函数式宏MC(A, B)
的调用,并将如上所述继续。但是,这次第一步失败,因为识别出两个参数但宏MC
只有一个参数。