可变宏中的无效参数计数

Invalid argument count in a variadic macro

本文关键字:参数 无效      更新时间:2023-10-16

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

#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。我错过了什么?有什么方法可以让它工作吗?

问题是Visual Studio扩展__VA_ARGS__后,他们被传递到后续的宏,而不是之前。这在过去也引起过问题,例如这里——为什么这个可变参数计数宏在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__))