我发现使用C风格宏和使用C++11中引入的新统一列表初始化表单之间似乎不兼容,但这类东西绝对不可能编写,这似乎令人难以置信,所以我认为我遗漏了一些东西。
问题是:当预处理器查找宏参数时,花括号似乎被忽略了。像MACR(Range{2,4})
这样的调用被误解为具有两个参数Range{2
和4
。在下面的代码中,一切都很好(好吧,糟糕的风格,但它有效),直到标记行:
#include <iostream>
using namespace std;
struct Range { int st, fn; };
ostream& operator << (ostream& out, const Range& r)
{ return out << "(" << r.st << "," << r.fn << ")"; }
#define COUT(X) (cout << (X) << endl)
int main()
{
COUT(3);
Range r {3,5};
COUT(r);
COUT(Range{3,5}); //this line won't compile
}
它给出以下错误消息:
badmacro.cpp:16:18: error: macro "COUT" passed 2 arguments, but takes just 1
COUT(Range{3,5});
^
compilation terminated due to -Wfatal-errors.
尤其是在使用旧库时,有时不可避免地要使用宏调用;在这种情况下,我们肯定不应该放弃新的语法吗?有官方的变通办法吗?
如果需要将表达式传递给现有宏,并且表达式包含未屏蔽的逗号,请将整个表达式括在括号中。
COUT((Range{3,5}));
丑吗?是的,但当你使用宏时就会发生这种情况。不要那样做。
如果它不是一个表达式,并且不能使用额外的括号,那么就不能使用该宏。
如果你正在写一个宏,而你不应该写,有时你可以写一个可变宏(如果你的编译器支持的话):
#define COUT(...) cout << (__VA_ARGS__) << endl;
预处理器宏只是编译前的高级文本替换。当调用宏时,预处理器对参数列表的解析很少。有一些逻辑可以区分嵌套括号内的逗号和外部的逗号,因此它知道哪些逗号属于宏本身的参数列表,哪些逗号属于嵌套函数调用的参数列表。例如:
macro(param1, param2, func(param1, param2) )
参数被解释为
param1
param2
func(param1, param2)
而不是
param1
param2
func(param1
param2)
在您的情况下,逗号不在嵌套括号内,因此预处理器最终将参数列表Range{3,5}
拆分为两个参数值
Range{3
5}
因此出现错误,因为宏只接受一个参数。预处理器没有任何上下文信息来知道Range{3,5}
应该被视为一个参数值。它只看到逗号并在上面拆分。
所以,为了解决你的问题,试着添加一对额外的括号:
COUT((Range{3,5}));
然后,预处理器应该解释一个参数值:
(Range{3,5})
它将创建以下语句供编译器使用:
(cout << ((Range{3,5})) << endl);