【问题标题】:Why is this macro being passed three arguments?为什么这个宏被传递了三个参数?
【发布时间】:2017-10-28 02:22:42
【问题描述】:
#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} ) );

【问题讨论】:

  • 您的结构声明-struct Foo { int a, b, c; }; 错误。应该是struct Foo { int a; int b; int c; };
  • @H.S.你确定吗?像这样的声明或 int a = 1, b = 2, c = 3;在课外都很好,除非在课堂上有针对这些的特殊规则......
  • 斑马鱼:哎呀..我的错,忽略我的评论。
  • 整个逗号也让我感到困惑。有一整篇关于 C 逗号运算符的维基百科文章,我只明白了一半,显然它评估所有逗号分隔的表达式,但只返回最后一个,所以在一个例子中,有人问下面的循环做了什么似乎有两个条件:for(i=0; j>=0, i

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


【解决方案1】:

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

假设你有宏

#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

【讨论】:

  • 这很奇怪,因为好像我将宏视为预处理器阶段中的简单粘贴作业,我希望 {1, 2, 3} 能够原封不动地通过。
  • @Zebrafish 它们是简单的粘贴作业,但并非那么那么简单。它们允许多个参数,因此必须有某种方法来拆分它们。我将在几秒钟内发布解决方法
  • 没关系,除非你有更好的方法,正如我提到的,如果我将它们包裹在另一组括号中,它工作正常。我并不是打算使用它,我只是在试验并试图找到更好的方法来缩短代码,但是当发生这种情况时我感到很惊讶。
  • push(Foo{1, 2, 3}) 被认为是 3 个参数,因为预处理器在 , 处原始拆分,忽略了花括号。您可以通过使用-E 标志编译来检查宏扩展,例如:godbolt.org/g/SzgpPF(中间的输出窗口显示结果)
  • 我明白了,所以这样做只是 #define push listOfFoos.pushback 而不是 #define push(x) listOfFoos.pushback(x) 有效。好的,谢谢。
猜你喜欢
  • 2016-09-21
  • 1970-01-01
  • 2019-06-27
  • 2012-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-17
相关资源
最近更新 更多