2017-04-16 56 views
0

在C++中,可变宏宏require at least one argument for the '...'。考虑以下功能:FOO(a, b, ...);如果我希望这两个调用都是正确且无警告的,我应该怎么做? FOO(5, 4, "gamma"); FOO(5, 4);我正在使用--pedantic标志,所以只是禁止警告不是一个选项。Variadic宏警告

第二个给出了上面提到的编译时警告。我认为这是:

将定义更改为FOO(a, ...);并将__VA_ARGS__变量(其代表...)拆分为b,如果存在,则将其分解成其余部分。所以函数调用看起来像这样:FOO(5, "4gamma");FOO(5, "4");这,我认为,这不是一个好的选择,因为分割效率不高,函数声明不需要b参数,即使它是强制性的。

有没有更好的方法来获得免警告编译?

+3

为什么使用宏?你试图解决的实际问题是什么? –

+0

可变参数函数模板是您的解决方案。 – DeiDei

+0

@DeiDei请你详细说明功能模板? – FigsHigs

回答

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); 
2
  • 你就可以摆脱这个宏,因为宏是邪恶的,与模板或别的东西代替它
  • 可以定义两个宏:FOOs - 有许多争论和FOO - 只有两个变元的
  • 你可以使用gcc ##__VA_ARGS__ extension(假设你正在使用gcc或兼容的编译器)
+0

但这意味着我将不得不'FOO(5,4); FOOs(5,4,“gamma”);',这与我想要的稍有不同。 – FigsHigs

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)可以由零或更多参数。