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

时间:2017-10-28 02:22:42

标签: c++ c++11 macros stdinitializerlist

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

  

错误:宏&#34;推&#34;传递3个参数,但只需1个

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

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

1 个答案:

答案 0 :(得分:4)

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

假设你有宏

#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的选项卡设置为-E以打开以检查宏扩展,总是很好。 Example