可变参数宏

时间:2016-07-05 17:18:08

标签: c++ visual-c++

我正在尝试创建一个宏,它将迭代定义的术语列表,并为每个调用另一个宏,可能还有其他参数列表。这是我得到的:

#define ITERATE_OVER_TERMS(MACRO, ...) \
MACRO(Term1, __VA_ARGS__) \
MACRO(Term2, __VA_ARGS__) \
MACRO(Term3, __VA_ARGS__) \
... and so on

但是,当我尝试在Visual Studio 2015中使用它时,我收到错误

warning C4003: not enough actual parameters for macro 'BODY'

其中BODY是作为MACRO参数传递的宏的名称。虽然技术上是一个警告,但它表明扩展出了问题。

为了缩小错误范围,我将我的示例简化为以下内容:

#include <iostream>

#define ITERATE(MACRO, ...) \
MACRO(1, __VA_ARGS__) MACRO(2, __VA_ARGS__)

#define BODY(IterationArg, Arg1, Arg2) \
std::cout << IterationArg << Arg1 << Arg2 << std::endl;

int main() {
  ITERATE(BODY, 8, 9)
    return 0;
}

它给出了如上所示的错误,而我希望它能够成功编译并生成输出

189
289

似乎用g ++编译,但不是Visual Studio。 我错过了什么?是否有一些解决方法可以解决这个问题?

1 个答案:

答案 0 :(得分:2)

问题是Visual Studio在传递到后续宏之后扩展__VA_ARGS__,而不是之前。这也引起了过去的问题,例如在这里 - Why does this variadic argument count macro fail with VC++?

在您的情况下,请考虑对代码进行简单更改:

#include <iostream>

#define ITERATE(MACRO, ...) \
MACRO(1, __VA_ARGS__) MACRO(2, __VA_ARGS__)

#define BODY(IterationArg, Arg1, Arg2) \
std::cout << #Arg1 << std::endl;

int main() {
  ITERATE(BODY, 8, 9)
    return 0;
}

参数#Arg1被字符串化,在输出中显示其内容:

8, 9
8, 9

不是我们的预期,是吗?

解决方案与链接问题中的解决方案相同:通过虚拟EXPAND宏强制扩展:

#define EXPAND(x) x

#define ITERATE(MACRO, ...) \
EXPAND(MACRO(1, __VA_ARGS__)) EXPAND(MACRO(2, __VA_ARGS__))

这样可以在VS和gcc中获得所需的结果。