为什么要向这个宏传递三个参数?

Why is this macro being passed three arguments?

#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 在在线编译器上编译时,我才得到一个更具描述性的错误:

error: macro "push" passed 3 arguments, but takes just 1

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

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

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

假设您有宏

#define foo(x, y, z)

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

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

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

其中 ... 的意思是,如果有任何额外的东西,就拿去 __VA_ARGS__ 的意思是 扩展到你得到的所有额外的东西.

提示:有一个标签总是很好 godbolt.org with compiler flags set to -E open to check macro expansion. Example