为什么我的可变参数宏不能正确接受任何参数?

时间:2017-10-17 15:43:21

标签: c++ c macros g++ variadic-macros

Overloading Macro on Number of Arguments

https://codecraft.co/2014/11/25/variadic-macros-tricks/

我一直在查看上面的两个链接,尝试使用以下代码:

#define _GET_NUMBER(_0, _1, _2, _3, _4, _5, NAME, ...) NAME
#define OUTPUT_ARGS_COUNT(...) _GET_NUMBER(_0, ##__VA_ARGS__, 5, 4, 3, 2, 1, 0)

...

cout << OUTPUT_ARGS_COUNT("HelloWorld", 1.2) << endl;
cout << OUTPUT_ARGS_COUNT("HelloWorld") << endl;
cout << OUTPUT_ARGS_COUNT() << endl;

编译,运行并提供以下输出:

2
1
1

我不能为我的生活弄清楚为什么调用OUTPUT_ARGS_COUNT()给我1而不是0.我对我正在尝试使用的代码有一个正确的理解,但它对我来说仍然有点希腊所以我猜我可能没有正确应用一些东西,尽管事实上我从堆栈溢出的链接中复制并粘贴了示例代码。

我正在使用g ++ 5.4.0 20160609进行编译。

非常感谢您指出的任何想法或其他资源。

2 个答案:

答案 0 :(得分:2)

您可以在http://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html看到:

  

其次,'##'标记粘贴运算符在逗号和变量参数之间具有特殊含义。如果你写

#define eprintf(format, ...) fprintf (stderr, format, ##__VA_ARGS__)
  

并且在使用eprintf宏时省略变量参数,然后将删除“##”之前的逗号。如果传递一个空参数,则不会发生这种情况,如果“##”前面的标记不是逗号,也不会发生这种情况。

eprintf ("success!\n")
 → fprintf(stderr, "success!\n");
  

上述解释对于唯一的宏参数是变量参数参数的情况是模棱两可的,因为尝试区分根本没有参数是空参数还是缺少参数是没有意义的。 CPP在符合特定C标准时保留逗号。否则,逗号将被删除作为标准的扩展名。

所以,(除非使用适当的扩展名)OUTPUT_ARGS_COUNT()被计为1个空参数(逗号与##__VA_ARGS__保持一致)。

答案 1 :(得分:2)

C标准指定

  

如果宏定义中的标识符列表没有以省略号结尾,[...]。否则, 调用中的参数应该多于宏定义中的参数(不包括...)

C2011 6.10.3/4;重点补充)

C ++ 11包含与第16.3 / 4段中相同效果的语言。

在这两种情况下,如果您的宏调用被解释为零参数,那么您的程序将是不符合的。另一方面,预处理器确实识别并支持空的宏参数 - 即由零预处理标记组成的参数。原则上,这里没有论证和单个空论证之间存在歧义,但在实践中,只有后一种解释才会产生一致的程序。

g ++选择后一种解释(另一个答案引用其文档为此效果)是合理和合适的,但如果您希望您的代码可移植,依赖它是不安全的。采用替代解释的编译器可能会有不同的行为,可能是通过提供您期望的行为,但也可能通过拒绝代码。