可变参数宏中的参数计数无效

Posted

技术标签:

【中文标题】可变参数宏中的参数计数无效【英文标题】:Invalid argument count in a variadic macro 【发布时间】:2016-07-05 17:18:08 【问题描述】:

我正在尝试创建一个宏,该宏将遍历已定义的术语列表,并为每个调用另一个宏,可能带有附加参数列表。这是我得到的:

#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 2015 仍然部分支持 C99 预处理器。来源:msdn.microsoft.com/en-us/library/hh567368.aspx @KABoissonneault 他们似乎支持可变参数宏很长时间了(msdn.microsoft.com/en-us/library/ms177415.aspx)VS2005 已经有版本了。 它们支持可变参数宏,但老实说,我从未见过作为宏参数传递的宏。 Visual Studio 可能希望您在 main 正文内评估 BODY 【参考方案1】:

问题是 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 中为您提供所需的结果。

【讨论】:

以上是关于可变参数宏中的参数计数无效的主要内容,如果未能解决你的问题,请参考以下文章

libreoffice calc - 宏中的可变参数

在指向另一个宏的可变参数宏中为每个参数添加前缀

可变宏中令牌的连接

找出可变参数宏中__VA_ARGS__的类型

可变宏参数计数未按预期工作

为啥这个嵌套的可变参数模板是无效参数?