在C ++中,可变参数宏require at least one argument for the '...'
。考虑一下这个函数:FOO(a, b, ...);
如果我希望这两个调用都是正确的并且没有警告,我该怎么办? FOO(5, 4, "gamma"); FOO(5, 4);
我使用--pedantic
标记,因此只是禁止警告。
第二个给出了上面提到的编译时警告。我考虑过这个:
将定义更改为FOO(a, ...);
并将__VA_ARGS__
变量(代表...)拆分为b
,如果存在,则分为其余部分。所以函数调用看起来像:FOO(5, "4gamma");
和FOO(5, "4");
我认为这不是一个好的选择,因为拆分效率不高,函数声明不需要b
参数,即使是强制性的。
有没有更好的方法来获得无警告编辑?
答案 0 :(得分:3)
虽然我完全同意,如果可能的话,应该使用可变函数或函数模板,这个问题也显示出对宏可以做什么和不可以做什么的一些误解,所以在这个答案中我将假装函数是不是一种选择。
将定义更改为
FOO(a, ...);
,并将__VA_ARGS__
变量(代表......)拆分为b
,如果存在,则分为其余部分。
是
所以函数调用看起来像:
FOO(5, "4gamma");
和FOO(5, "4");
没有。继续调用FOO(5, 4, "gamma");
和FOO(5, 4);
。在第一种情况下,__VA_ARGS__
是4, "gamma"
。在第二种情况下,__VA_ARGS__
为4
。
如果需要从前者中提取, "gamma"
,可以由预处理器完成。它需要参数数量的上限,但您可以将其增加到您喜欢的任何数字。虽然很难看。
如果__VA_ARGS__
不包含逗号,则提取很简单:
#define COMMA_TRAILING_ARGS_0(a)
如果您知道__VA_ARGS__
至少包含一个逗号,则可以使用
#define COMMA_TRAILING_ARGS_1(a, ...) , __VA_ARGS__
你可以检测出哪些要使用,最多可达宏观参数的上限:
#define ARG16(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, ...) _16
#define HAS_COMMA(...) ARG16(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, )
组合:
#define COMMA_TRAILING_ARGS_0(a)
#define COMMA_TRAILING_ARGS_1(a, ...) , __VA_ARGS__
#define ARG16(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, ...) _16
#define HAS_COMMA(...) ARG16(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,)
#define CONCAT(a, b) a ## b
#define CONCAT_(a, b) CONCAT(a, b)
#define FOO(a, ...) BAR(a CONCAT_(COMMA_TRAILING_ARGS_, HAS_COMMA(__VA_ARGS__)) (__VA_ARGS__))
FOO(5, 4, x, q); // expands to BAR(5, x, q);
FOO(5, 4, "gamma"); // expands to BAR(5, "gamma");
FOO(5, 4); // expands to BAR(5);
答案 1 :(得分:2)
FOOs
- 有很多参数和FOO
- 只有两个论点##__VA_ARGS__
extension(假设您使用的是gcc或兼容的编译器)答案 2 :(得分:1)
我不明白你的具体问题,但从你所展示的内容来看,使用两个重载函数要容易得多。
void foo(int, int);
void foo(int, int, const std::string&);
foo(3, 4); // calls first
foo(3, 4, "hello"); // calls second
或者甚至可能:
void foo(int, int, const std::string& = "");
另一方面,如果你可以使用C ++ 11:
template<typename... Args>
void foo(int, int, const Args&... args); // google variadic templates
参数包(args
)可以包含零个或多个参数。