首页 > 解决方案 > 带有 __VA_ARGS__ 的嵌套宏不展开

问题描述

为了获得数量__VA__ARGS__,我阅读了这个答案并且它有效。但我觉得那PP_NARG_是多余的,我看不出为什么PP_RSEQ_N是宏功能。所以我修改代码如下

#include <assert.h>
#define PP_RSEQ_N \
         63,62,61,60,                   \
         59,58,57,56,55,54,53,52,51,50, \
         49,48,47,46,45,44,43,42,41,40, \
         39,38,37,36,35,34,33,32,31,30, \
         29,28,27,26,25,24,23,22,21,20, \
         19,18,17,16,15,14,13,12,11,10, \
         9,8,7,6,5,4,3,2,1,0
#define PP_NARG(...) \
         PP_ARG_N(__VA_ARGS__,PP_RSEQ_N)
#define PP_ARG_N( \
          _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
         _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
         _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
         _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
         _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
         _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
         _61,_62,_63,N,...) N

/* Some test cases */

int main() {
  assert(PP_NARG(1,2,"yes",!)==4);
}

我收到错误和注释。

main.c:24:33: error: macro "PP_ARG_N" requires 65 arguments, but only 5 given
   assert(PP_NARG(1,2,"yes",!)==4);
                                 ^

似乎 ,PP_NARG没有PP_RSEQ_N展开。但为什么?我知道使用#and ##,宏不会被扩展,但事实并非如此。

另外我想知道为什么这个答案PP_NARG_是必要的,为什么是宏函数,而不是普通的宏(无参数)?PP_RSEQ_N

标签: c++cmacros

解决方案


宏调用的本质是宏参数不会在宏调用中展开。标准第 6.10.3.1 节规定了精确的程序。

  1. 在确定了调用类函数宏的参数后,将进行参数替换。

因此,宏的参数由当时实际存在于令牌流中的逗号分隔,而不管替换的参数可能是什么样的。

一旦收集了参数,宏体中宏参数的使用将被参数替换。在大多数情况下,此时参数会被扩展,但是(如您所见)如果参数用作#or##表达式的一部分,则参数不会被宏替换为该 use。此外,宏体中根本不需要使用参数,因此在这种情况下,根本不需要扩展参数。

一旦宏参数被相应的参数替换并且###运算符被评估,生成的令牌流通过宏处理器传回。在此重新扫描期间,宏主体中使用的任何宏都将被扩展。

现在,作者PP_NARG实际上想要构造一个宏调用,该宏调用由原始可变参数参数 toPP_NARG后跟PP_RSEQ_N. 由于宏参数PP_RSEQ_N的扩展直到它出现的宏调用的扩展才会发生,因此有必要引入额外的宏扩展级别;该PP_NARG_宏用于构造对PP_NARG. (您可以通过完全不使用来避免这种PP_RSEQ_N情况,而是将倒计时直接放在对 的调用中PP_NARG。但是有很多理由可以避免这种解决方案;添加额外级别的宏替换更简洁。)

将宏定义为不带参数的类函数宏而不是简单宏的通常原因PP_RSEQ_N是能够在不扩展宏的情况下传递宏的名称。在此代码段中似​​乎并非如此,但它可能出现在从中提取代码段的代码的其他地方。


推荐阅读