2017-10-17 124 views
1

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.

任何意见或其他资源你可以点我编译到将不胜感激。

+1

你可以看到http://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html:*“上面的解释是含糊不清的,唯一的宏参数是一个可变参数参数的情况下,因为它没有意义来区分是否没有论证是一个空的论证还是缺少的论证,CPP在符合特定的C标准时保留逗号,否则逗号将作为标准的扩展删除。 – Jarod42

+0

选中此https://stackoverflow.com/questions/2308243/macro-returning-the-number-of-arguments-it-is-given-in-c,该解决方案也有失败的零个参数 –

回答

1

C标准规定

如果标识符列表中的宏定义不与省略号结束,[...]。否则,应当有更多的参数在所述调用以外还有宏定义参数(不包括...)

C2011 6.10.3/4;强调)

C++ 11包含在第16.3/4段中也有同样的效果。

在这两种情况下,那么,如果您的宏调用被解释为具有零个参数那么你的程序是不符合要求的。另一方面,预处理器确实支持空的宏参数 - 即由零预处理标记组成的参数。那么原则上,在没有论证和单一的空论证之间存在一个模棱两可的问题,但实际上,只有后者的解释导致了一致的程序。

使得G ++选择采用后者解释(对方的回答引用它的文档类似的效果)因此是合理和适当的,但如果你想你的代码是便携式的它是不是安全依靠它。采用替代解释的编译器行为会有所不同,可能通过提供您期望的行为,但也可能通过拒绝代码。

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"); 

以上的说明是不明确的关于其中唯一的宏参数是一个可变参数的参数的情况下,因为它是没有意义的,试图区分完全没有参数是否是一个空的参数或缺少论据。符合特定C标准时,CPP保留逗号。否则,逗号将作为标准的扩展而丢弃。

因此,(除非使用适当的扩展名)OUTPUT_ARGS_COUNT()被计为1个空参数(逗号与##__VA_ARGS__保留)。

+0

我看到的文档在你对我原来的帖子发表评论之后,但我不知道要修改它,所以我可以在调用OUTPUT_ARGS_COUNT()时得到0。你认为这是不可能的吗?或者我可能只是不理解你所指的适当的扩展名。 – Brian

+1

正如你可以在[演示]见(http://coliru.stacked-crooked.com/a/090b4438717735c3),'-std = GNU ++ XX'给出'0'而'-std = C++ XX '给出'1'。你甚至对这个构造有明确的警告。 – Jarod42

+1

@Brian:如引用中所述,它取决于您正在编译的std版本。如果你用'-std = c99'编译,你会得到你显示的输出。另一方面,如果你使用'-std = gnu99',你会得到'2 1 0'。 –

相关问题