如何将C风格的宏与C++11风格的构造函数调用一起使用



我发现使用C风格宏和使用C++11中引入的新统一列表初始化表单之间似乎不兼容,但这类东西绝对不可能编写,这似乎令人难以置信,所以我认为我遗漏了一些东西。

问题是:当预处理器查找宏参数时,花括号似乎被忽略了。像MACR(Range{2,4})这样的调用被误解为具有两个参数Range{24。在下面的代码中,一切都很好(好吧,糟糕的风格,但它有效),直到标记行:

#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);

最新更新