带C+的可选参数+;宏 有没有用C++宏获取可选参数的方法?某种重载也不错。

带C+的可选参数+;宏 有没有用C++宏获取可选参数的方法?某种重载也不错。,c++,macros,C++,Macros,在调用时,您知道要传入多少arg,因此实际上不需要重载。这里有一种方法。它使用参数列表两次,首先形成helper宏的名称,然后将参数传递给该helper宏。它使用标准的技巧来计算宏的参数数量 enum { plain = 0, bold = 1, italic = 2 }; void PrintString(const char* message, int size, int style) { } #define PRINT_STRING_1_ARGS(message

/
g++
支持,但我认为这不是标准配置,所以使用它的风险自负。

C++宏没有从C更改。因为C没有函数的重载和默认参数,所以它肯定没有宏的默认参数。所以要回答你的问题:不,这些功能对于宏来说是不存在的。您唯一的选择是使用不同的名称定义多个宏(或者根本不使用宏)


作为旁注:在C++中,尽可能地远离宏通常被认为是好的实践。如果您需要这样的功能,很有可能您过度使用了宏。

根据您的需要,您可以使用宏。现在,对于可选参数或宏重载,没有这样的事情。

这不是预处理器设计的真正目的

这就是说,如果你想进入一个极具挑战性的宏编程领域,并且具有一定的可读性,你应该看看下面的例子。毕竟,如果没有三个完全图灵兼容的编程级别(预处理器、模板元编程和基础级C++),它就不是C++了!p>
在调用时,您知道要传入多少arg,因此实际上不需要重载。

这里有一种方法。它使用参数列表两次,首先形成helper宏的名称,然后将参数传递给该helper宏。它使用标准的技巧来计算宏的参数数量

enum
{
    plain = 0,
    bold = 1,
    italic = 2
};

void PrintString(const char* message, int size, int style)
{
}

#define PRINT_STRING_1_ARGS(message)              PrintString(message, 0, 0)
#define PRINT_STRING_2_ARGS(message, size)        PrintString(message, size, 0)
#define PRINT_STRING_3_ARGS(message, size, style) PrintString(message, size, style)

#define GET_4TH_ARG(arg1, arg2, arg3, arg4, ...) arg4
#define PRINT_STRING_MACRO_CHOOSER(...) \
    GET_4TH_ARG(__VA_ARGS__, PRINT_STRING_3_ARGS, \
                PRINT_STRING_2_ARGS, PRINT_STRING_1_ARGS, )

#define PRINT_STRING(...) PRINT_STRING_MACRO_CHOOSER(__VA_ARGS__)(__VA_ARGS__)

int main(int argc, char * const argv[])
{
    PRINT_STRING("Hello, World!");
    PRINT_STRING("Hello, World!", 18);
    PRINT_STRING("Hello, World!", 18, bold);

    return 0;
}
这使宏的调用者(而不是编写者)更加容易

#包括
#include <stdio.h>

#define PP_NARG(...) \
    PP_NARG_(__VA_ARGS__,PP_RSEQ_N())
#define PP_NARG_(...) \
    PP_ARG_N(__VA_ARGS__)
#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
#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_CONCAT(a,b) PP_CONCAT_(a,b)
#define PP_CONCAT_(a,b) a ## b

#define THINK(...) PP_CONCAT(THINK_, PP_NARG(__VA_ARGS__))(__VA_ARGS__)
#define THINK_0() THINK_1("sector zz9 plural z alpha")
#define THINK_1(location) THINK_2(location, 42)
#define THINK_2(location,answer) THINK_3(location, answer, "deep thought")
#define THINK_3(location,answer,computer) \
  printf ("The answer is %d. This was calculated by %s, and a computer to figure out what this"
          " actually means will be build in %s\n", (answer), (computer), (location))

int
main (int argc, char *argv[])
{
  THINK (); /* On compilers other than GCC you have to call with least one non-default argument */
}
#定义PP_NARG(…)\ PP_NARG_uu(uu VA_ARGS_uu,PP_RSEQ_N()) #定义PP_NARG_(…)\ PP_ARG_N(uu VA_ARGS_uu) #定义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 #定义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 #定义PP_CONCAT(a,b)PP_CONCAT(a,b) #定义PP_CONCAT(a,b)a##b #定义THINK(…)PP_CONCAT(THINK_u,PP_NARG(uu VA_ARGS_uu))(u VA_ARGS_u) #定义THINK_0()THINK_1(“扇区zz9复数z alpha”) #定义THINK_1(位置)THINK_2(位置,42) #定义思考2(位置,答案)思考3(位置,答案,“深入思考”) #定义思考3(位置、答案、计算机)\ printf(“答案是%d。这是由%s和一台计算机计算出来的” “实际上意味着将在%s中生成\n”,(答案),(计算机),(位置)) int main(int argc,char*argv[]) { THINK();/*在除GCC之外的编译器上,您必须使用至少一个非默认参数进行调用*/ }

免责声明:基本上是无害的。

非常尊重德里克·莱德贝特的回答,并为重新提出一个老问题表示歉意

了解它在做什么,并在其他地方学习使用
####
处理
u VA_uargs_uu
的能力,这让我想到了一个变体

// The multiple macros that you would need anyway [as per: Crazy Eddie]
#define XXX_0()                     <code for no arguments> 
#define XXX_1(A)                    <code for one argument> 
#define XXX_2(A,B)                  <code for two arguments> 
#define XXX_3(A,B,C)                <code for three arguments> 
#define XXX_4(A,B,C,D)              <code for four arguments>  

// The interim macro that simply strips the excess and ends up with the required macro
#define XXX_X(x,A,B,C,D,FUNC, ...)  FUNC  

// The macro that the programmer uses 
#define XXX(...)                    XXX_X(,##__VA_ARGS__,\
                                          XXX_4(__VA_ARGS__),\
                                          XXX_3(__VA_ARGS__),\
                                          XXX_2(__VA_ARGS__),\
                                          XXX_1(__VA_ARGS__),\
                                          XXX_0(__VA_ARGS__)\
                                         ) 
变成

XXX_X(, XXX_4(), XXX_3(),  XXX_2(),    XXX_1(),      XXX_0()         );
XXX_X(, 1,       XXX_4(1), XXX_3(1),   XXX_2(1),     XXX_1(1),       XXX_0(1)          );
XXX_X(, 1,       2,        XXX_4(1,2), XXX_3(1,2),   XXX_2(1,2),     XXX_1(1,2),       XXX_0(1,2)        );
XXX_X(, 1,       2,        3,          XXX_4(1,2,3), XXX_3(1,2,3),   XXX_2(1,2,3),     XXX_1(1,2,3),     XXX_0(1,2,3)      );
XXX_X(, 1,       2,        3,          4,            XXX_4(1,2,3,4), XXX_3(1,2,3,4),   XXX_2(1,2,3,4),   XXX_1(1,2,3,4),   XXX_0(1,2,3,4)    );
XXX_X(, 1,       2,        3,          4,            5,              XXX_4(1,2,3,4,5), XXX_3(1,2,3,4,5), XXX_2(1,2,3,4,5), XXX_1(1,2,3,4,5), XXX_0(1,2,3,4,5) );
这只是第六个论点

XXX_0(); 
XXX_1(1); 
XXX_2(1,2); 
XXX_3(1,2,3); 
XXX_4(1,2,3,4); 
5; 
PS:删除#define for XXX_0以获取编译错误[即:如果不允许使用无参数选项]

PPS:如果无效的情况(例如:5)能够给程序员一个更清晰的编译错误,那就太好了


购买力平价:我不是专家,所以我很高兴听到评论(好的、坏的或其他的)

以上使用宏计算参数的示例(来自德里克·莱德贝特、大卫·索科夫斯基和乔·D)都不适用于我使用Microsoft VCC 10。
\uu VA\u ARGS\uuuu
参数始终被视为一个单独的参数(是否使用
##
标记它),因此这些示例所依赖的参数转换不起作用


<> P> >,如上面许多其他人所说的:“不,你不能超载宏或使用可选的参数。”< P> > P>对于任何使用Visual C++工作的VAYNARGS解决方案,任何人都痛苦地搜索。在Visual C++ Express 2010中:为我完美地工作(也有零参数!):

#define VA_NUM_ARGS_IMPL(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,N,...) N
#define VA_NUM_ARGS_IMPL_(tuple) VA_NUM_ARGS_IMPL tuple
#define VA_NARGS(...)  bool(#__VA_ARGS__) ? (VA_NUM_ARGS_IMPL_((__VA_ARGS__, 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
如果需要具有可选参数的宏,可以执行以下操作:

//macro selection(vc++)
#define SELMACRO_IMPL(_1,_2,_3, N,...) N
#define SELMACRO_IMPL_(tuple) SELMACRO_IMPL tuple
#define mymacro1(var1) var1
#define mymacro2(var1,var2) var2*var1
#define mymacro3(var1,var2,var3) var1*var2*var3
#define mymacro(...) SELMACRO_IMPL_((__VA_ARGS__, mymacro3(__VA_ARGS__), mymacro2(__VA_ARGS__), mymacro1(__VA_ARGS__))) 
这对我来说在vc也很管用。但它不适用于零参数

int x=99;
x=mymacro(2);//2
x=mymacro(2,2);//4
x=mymacro(2,2,2);//8

Derek Ledbetter代码的更简洁版本:

enum
{
    plain = 0,
    bold = 1,
    italic = 2
};


void PrintString(const char* message = NULL, int size = 0, int style = 0)
{
}


#define PRINT_STRING(...) PrintString(__VA_ARGS__)


int main(int argc, char * const argv[])
{ 
    PRINT_STRING("Hello, World!");
    PRINT_STRING("Hello, World!", 18);
    PRINT_STRING("Hello, World!", 18, bold);

    return 0;
}
最尊敬的是德里克·莱德贝特,大卫·索科夫斯基,他们的答案是Syphoralate,以及Jens Gustedt在

最后,我提出了一个包含所有技巧的解决方案

  • 仅使用标准C99宏来实现函数重载,不涉及GCC/CLANG/MSVC扩展(即,通过特定表达式
    进行逗号吞咽,对于GCC/CLANG使用###(u#)VA(u参数)(u#u)VA(u参数)()(u))u))(代码>进行隐式吞咽)。因此,如果您愿意,可以将缺少的
    --std=c99
    传递给编译器。)
  • 适用于零参数,以及无限数量的参数,如果您进一步扩展它以满足您的需要
  • 合理地跨平台工作,至少经过测试

    • GNU/Linux+GCC(CentOS 7.0 x8664上的GCC 4.9.2)
    • GNU/Linux+CLANG/LLVM,(CentOS 7.0 x86_64上的CLANG/LLVM 3.5.0)
    • OS X+Xcode,(OS X Yosemite 10.10.1上的Xcode 6.1.1)
    • Windows+Visual Studio,(Visual Studio 2013年第4次更新,W
      int x=99;
      x=mymacro(2);//2
      x=mymacro(2,2);//4
      x=mymacro(2,2,2);//8
      
      enum
      {
          plain = 0,
          bold = 1,
          italic = 2
      };
      
      
      void PrintString(const char* message = NULL, int size = 0, int style = 0)
      {
      }
      
      
      #define PRINT_STRING(...) PrintString(__VA_ARGS__)
      
      
      int main(int argc, char * const argv[])
      { 
          PRINT_STRING("Hello, World!");
          PRINT_STRING("Hello, World!", 18);
          PRINT_STRING("Hello, World!", 18, bold);
      
          return 0;
      }
      
      #define create(...) MACRO_CHOOSER(__VA_ARGS__)(__VA_ARGS__)
      
      void realCreate(int x, int y)
      {
        printf("(%d, %d)\n", x, y);
      }
      
      #define CREATE_2(x, y) realCreate(x, y)
      #define CREATE_1(x) CREATE_2(x, 0)
      #define CREATE_0() CREATE_1(0)
      
      NO_ARG_EXPANDER __VA_ARGS__ ()  // simply shrinks to NO_ARG_EXPANDER()
      
      #define NO_ARG_EXPANDER() ,,CREATE_0
      
      #define MACRO_CHOOSER(...) CHOOSE_FROM_ARG_COUNT(NO_ARG_EXPANDER __VA_ARGS__ ())
      
      create();
      create(10);
      create(20, 20);
      
      CHOOSE_FROM_ARG_COUNT(,,CREATE_0)();
      CHOOSE_FROM_ARG_COUNT(NO_ARG_EXPANDER 10 ())(10);
      CHOOSE_FROM_ARG_COUNT(NO_ARG_EXPANDER 20, 20 ())(20, 20);
      
      ##define CHOOSE_FROM_ARG_COUNT(...) \
        FUNC_RECOMPOSER((__VA_ARGS__, CREATE_2, CREATE_1, ))
      #define FUNC_RECOMPOSER(argsWithParentheses) \
        FUNC_CHOOSER argsWithParentheses
      
      FUNC_CHOOSER (,,CREATE_0, CREATE_2, CREATE_1, )();
      FUNC_CHOOSER (NO_ARG_EXPANDER 10 (), CREATE_2, CREATE_1, )(10);
      FUNC_CHOOSER (NO_ARG_EXPANDER 20, 20 (), CREATE_2, CREATE_1, )(20, 20);
      
      #define FUNC_CHOOSER(_f1, _f2, _f3, ...) _f3
      
      CREATE_0();
      CREATE_1(10);
      CREATE_2(20, 20);
      
      realCreate(0, 0);
      realCreate(10, 10);
      realCreate(20, 20);
      
      #include <stdio.h>
      
      void realCreate(int x, int y)
      {
        printf("(%d, %d)\n", x, y);
      }
      
      #define CREATE_2(x, y) realCreate(x, y)
      #define CREATE_1(x) CREATE_2(x, 0)
      #define CREATE_0() CREATE_1(0)
      
      #define FUNC_CHOOSER(_f1, _f2, _f3, ...) _f3
      #define FUNC_RECOMPOSER(argsWithParentheses) FUNC_CHOOSER argsWithParentheses
      #define CHOOSE_FROM_ARG_COUNT(...) FUNC_RECOMPOSER((__VA_ARGS__, CREATE_2, CREATE_1, ))
      #define NO_ARG_EXPANDER() ,,CREATE_0
      #define MACRO_CHOOSER(...) CHOOSE_FROM_ARG_COUNT(NO_ARG_EXPANDER __VA_ARGS__ ())
      #define create(...) MACRO_CHOOSER(__VA_ARGS__)(__VA_ARGS__)
      
      int main()
      {
        create();
        create(10);
        create(20, 20);
        //create(30, 30, 30);  // Compilation error
        return 0;
      }
      
      #include <boost/preprocessor/facilities/overload.hpp>
      #include <boost/preprocessor/cat.hpp>
      #include <boost/preprocessor/facilities/empty.hpp>
      #include <boost/preprocessor/arithmetic/add.hpp>
      
      #define MACRO_1(number) MACRO_2(number,10)
      #define MACRO_2(number1,number2) BOOST_PP_ADD(number1,number2)
      
      #if !BOOST_PP_VARIADICS_MSVC
      
      #define MACRO_ADD_NUMBERS(...) BOOST_PP_OVERLOAD(MACRO_,__VA_ARGS__)(__VA_ARGS__)
      
      #else
      
      // or for Visual C++
      
      #define MACRO_ADD_NUMBERS(...) \
        BOOST_PP_CAT(BOOST_PP_OVERLOAD(MACRO_,__VA_ARGS__)(__VA_ARGS__),BOOST_PP_EMPTY())
      
      #endif
      
      MACRO_ADD_NUMBERS(5) // output is 15
      MACRO_ADD_NUMBERS(3,6) // output is 9
      
      #include <stdio.h>
      
      void realCreate(int x, int y)
      {
          printf("(%d, %d)\n", x, y);
      }
      
      // This part you put in some library header:
      #define FUNC_CHOOSER(_f0, _f1, _f2, _f3, _f4, _f5, _f6, _f7, _f8, _f9, _f10, _f11, _f12, _f13, _f14, _f15, _f16, ...) _f16
      #define FUNC_RECOMPOSER(argsWithParentheses) FUNC_CHOOSER argsWithParentheses
      #define CHOOSE_FROM_ARG_COUNT(F, ...) FUNC_RECOMPOSER((__VA_ARGS__, \
                  F##_16, F##_15, F##_14, F##_13, F##_12, F##_11, F##_10, F##_9, F##_8,\
                  F##_7, F##_6, F##_5, F##_4, F##_3, F##_2, F##_1, ))
      #define NO_ARG_EXPANDER(FUNC) ,,,,,,,,,,,,,,,,FUNC ## _0
      #define MACRO_CHOOSER(FUNC, ...) CHOOSE_FROM_ARG_COUNT(FUNC, NO_ARG_EXPANDER __VA_ARGS__ (FUNC))
      #define MULTI_MACRO(FUNC, ...) MACRO_CHOOSER(FUNC, __VA_ARGS__)(__VA_ARGS__)
      
      // When you need to make a macro with default arguments, use this:
      #define create(...) MULTI_MACRO(CREATE, __VA_ARGS__)
      #define CREATE_0() CREATE_1(0)
      #define CREATE_1(x) CREATE_2(x, 0)
      #define CREATE_2(x, y) \
          do { \
              /* put whatever code you want in the last macro */ \
              realCreate(x, y); \
          } while(0)
      
      
      int main()
      {
          create();
          create(10);
          create(20, 20);
          //create(30, 30, 30);  // Compilation error
          return 0;
      }