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

标签 c++ visual-c++ macros variadic-macros

所以,基本上我正在尝试实现一个宏来计算 VA_ARGS 中的参数数量。

为了简单起见,它最多只能使用 3 个参数。问题是,当宏使用少于 3 个参数时,它不起作用,并触发“预期表达式”错误。

#define EXPAND( x ) x
#define PP_NARG(...) EXPAND(PP_ARG_N(__VA_ARGS__, PP_RSEQ_N()))
#define PP_ARG_N(_1, _2, _3, N,...) N
#define PP_RSEQ_N() 3,2,1,0

void main()
{
    printf("\nTEST PP_NARG: %i", PP_NARG());        //Doesn't work (in this case it shouldn't work, so it's correct)
    printf("\nTEST PP_NARG: %i", PP_NARG(0));       //Doesn't work
    printf("\nTEST PP_NARG: %i", PP_NARG(0,0));     //Doesn't work
    printf("\nTEST PP_NARG: %i", PP_NARG(0,0,0));   //Works
}

仅保留有效的行即可正确编译并打印“TEST PP_NARG: 3”。

我认为问题可能是 PP_RSEQ_N() 由于某种原因仅扩展到“3”,而不是“3,2,1,0”,因为即使 PP_RSEQ_N() 被定义为这样

#define PP_RSEQ_N() 10,9,8,7,6,5,4,3,2,1,0

它仍然无法使用少于 3 个参数。

我正在使用 MSVC 编译器,这可能是问题的原因,因为它对于宏的表现不太好,如下所示:MSVC doesn't expand __VA_ARGS__ correctly

最佳答案

在您的实现中,PP_RSEQ_N()PP_ARG_N 的参数。作为参数,它仅在预处理的参数替换阶段进行扩展,但这仅在替换其替换列表中的参数之前发生(只要在替换列表中,它没有被替换)字符串化并且不参与粘贴)。

由于 PP_ARG_N 在其替换列表中只有第四个参数 N,因此 PP_RSEQ_N() 仅当您碰巧传递三个参数时才会扩展(在重新扫描和替换阶段有第二次扫描,它在参数替换后应用......但这在这里没有效果,因为 PP_RSEQ_N() 在一个电话)。

删除这个宏并将其放入 PP_NARG 中,如下所示:

#define EXPAND( x ) x
#define PP_NARG(...) EXPAND(PP_ARG_N(__VA_ARGS__, 3,2,1,0))
#define PP_ARG_N(_1, _2, _3, N,...) N

...事情“工作”正常:

PP_NARG() 扩展为 1
PP_NARG(x) 扩展为 1
PP_NARG(x,y) 扩展为 2

但是请注意,PP_NARG() 不会给您 0。可以说这实际上是正确的;对于预处理器,这不是传递零参数。它正在传递一个空的参数。这与 #define X(A) OPEN A CLOSE/X() 产生 OPEN CLOSE 是一样的。如果出于某种原因你希望它扩展到 0,可能需要一些技巧来实现这一点,但对于这个答案,我只专注于让你克服这一困难。

关于c++ - 可变参数宏参数计数未按预期工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45787224/

相关文章:

c++ - 如何使用 C++ 通过 WebBrowser 控件以编程方式更改打印机设置?

c++ - 更改代码生成后以代码 255 退出的特定代码行

C++ 变量声明被视为函数声明

c++ - 是否可以从宏定义宏

c - 语义宏 - 将前一个宏分配给另一个宏

c++ - 有没有办法决定模板类的模板参数类型?

c++ - 如何否定 gtest assert 或 expect that 中的匹配器?

c++ - 二进制文件加密问题

c++ - 使用 "expected a string literal, but found a user-defined string literal instead"C"'时是什么导致错误 'extern "?

map - Clojure 宏中关键字的奇怪行为