1
#include <vector>

struct Foo { int a, b, c; };

int main()
{
    Foo myFoo = Foo{ 1, 2, 3 };

    std::vector<Foo> listOfFoos;
    listOfFoos.push_back(Foo{ 1, 2, 3 });


#define push(x) listOfFoos.push_back(x)

    push(Foo{ 1, 2, 3 } ); // Error

}

错误是:

> "Expected a '}'"  
> "Syntax error: expected a ')' not '}'"  "Syntax
> error: missing ')' before ';'"

我在 Visual Studio 上花了很长时间才试图弄清楚发生了什么。直到我在使用 GCC 的在线编译器上编译时,我才得到一个更具描述性的错误:

错误:宏“push”传递了 3 个参数,但只需要 1 个

我想我很困惑,因为我认为 std::initializer_list 是一个结构,应该作为一个传递。当它抱怨将 3 个参数传递给宏时,它是在说 push({1, 2, 3}); 我正在做相当于 push(1, 2, 3);? 这似乎 std::initializer_list 在解析宏时在预编译器阶段之前对其元素进行了一种扩展。我不明白这是为什么。另外,我尝试将它包装在另一组括号中并且它有效:

push( ( {1, 2, 3} ) );
4

1 回答 1

4

宏非常原始且有限,它们(不一定)对所使用的编程语言一无所知。

假设你有宏

#define foo(x, y, z)

并像foo(1, 2, 3). 预处理器在逗号 ( ,) 处拆分并将变量x,yz相应地设置为输入数字。在您的宏调用中push(Foo{ 1, 2, 3 } ),这并没有什么不同。它以逗号分隔并设置xFoo{ 1. 但是,还有两个值23 },因此出现错误。花括号对于预处理器来说没有任何特殊之处,它只是另一个字母。

通过 传递所有内容,而不是采用一个参数,而是将其作为 va-args:

#define push(...) listOfFoos.push_back(__VA_ARGS__)

where...意味着,如果有任何额外的东西,就拿走它__VA_ARGS__意味着扩展到你得到的所有东西 extra

提示:在godbolt.org上设置一个选项卡并设置打开编译器标志-E以检查宏扩展总是很好的。例子

于 2017-10-28T02:28:16.990 回答