可变参数宏警告
Variadic macro warning
在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
参数,即使它是强制性的。
有没有更好的方法来获得无警告的编译?
尽管我完全同意,如果可能的话,应该使用可变参数函数或函数模板,但这个问题也显示出对宏可以做什么和不能做什么的一些误解,所以在这个答案中,我将假装函数不是一种选择。
将定义更改为
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);
- 你可以摆脱这个宏,因为宏是邪恶的,并用模板或其他东西替换它
- 您可以定义两个宏:
FOOs
- 具有许多参数和FOO
- 仅使用两个参数 - 您可以使用 GCC
##__VA_ARGS__
扩展(假设您使用的是 GCC 或兼容的编译器)
我不明白你的具体问题,但从你展示的内容来看,使用两个重载函数要容易得多。
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
)可以由零个或多个参数组成。
- 警告:忽略模板参数上的属性..在 std::unique_ptr (-wignore 属性)的声明中
- 将不同类型的模板参数包提取到双精度向量中会产生警告
- OPENCL 警告:不兼容的指针类型将'float __global[16]'传递给类型为 '__global float4 的参数 *
- "(void) cast"与功能有什么区别 "__attributes__"来沉默未使用的参数警告?
- 宏函数调用缺少参数警告,即使给定了参数
- 警告 C4267"参数":从"size_t"转换为"DWORD&quo
- C++程序给出了太多参数警告
- 如何使用布尔参数为按位运算符启用C++警告
- 编译器在 const ref 类型参数上使用临时对象时是否应该警告不安全的行为?
- 如何警告 C 中 void 指针上的参数不兼容的类型
- q致命参数:将 QString 转换为常量字符* 会导致警告"format string is not a string literal"
- 当没有显式关键字与单参数构造函数一起使用时,编译器可以发出警告
- 由于非类型模板参数而具有零大小数组的类模板:如何防止警告
- 为什么在相同大小的功能参数中隐式转换不会发出警告
- 可变参数宏警告
- 警告:用两个参数构造函数返回对象时,表达结果未使用
- 在基于模板参数的模板实例化时发出警告
- clang:警告:编译期间未使用的参数:"-stdlib=libc++"
- 警告:格式"%d"需要类型为"int*"的参数,但参数5的类型为"in
- GCC警告的含义:忽略模板参数上的属性(-Wignored属性)