262

I have two macros FOO2 and FOO3:

#define FOO2(x,y) ... #define FOO3(x,y,z) ... 

I want to define a new macro FOO as follows:

#define FOO(x,y) FOO2(x,y) #define FOO(x,y,z) FOO3(x,y,z) 

But this doesn't work because macros do not overload on number of arguments.

Without modifying FOO2 and FOO3, is there some way to define a macro FOO (using __VA_ARGS__ or otherwise) to get the same effect of dispatching FOO(x,y) to FOO2, and FOO(x,y,z) to FOO3?

6

11 Answers 11

396

Simple as:

#define EXPAND(x) x #define GET_MACRO(_1, _2, _3, name, ...) name #define FOO(...) EXPAND( GET_MACRO(__VA_ARGS__, FOO3, FOO2)(__VA_ARGS__) ) 

With the above definitions the "overloaded" FOO macro expands like this:

FOO(a, b) // expands to FOO2(a, b) FOO(a, b, c) // expands to FOO3(a, b, c) 

Live demo.

Sign up to request clarification or add additional context in comments.

13 Comments

@Uroc327 Adding a 0-argument macro to the list is possible, see my answer.
Does not work on Microsoft Visual Studio 2010, VA_ARGS seems to be expanded into a single macro argument.
Found this answer to make it work under MSVC 2010.
If anybody's confused as to how to use the EXPAND mentioned in @Étienne's link, you basically invoke it on GET_MACRO like so #define FOO(...) EXPAND(GET_MACRO(__VA_ARGS__, FOO3, FOO2, FOO1)(__VA_ARGS__)) and it should expand to the right number of arguments in msvc.
Note that on C++11, you'll get a warning: ISO C++11 requires at least one argument for the "..." in a variadic macro. To fix this, add an unused argument (or even just a comma) after the last param in the definition of FOO(...): #define FOO(...) GET_MACRO(__VA_ARGS__, FOO3, FOO2, UNUSED)(__VA_ARGS__) (See it run on Coliru).
|
78

To add on to netcoder's answer, you CAN in fact do this with a 0-argument macro, with the help of the GCC ##__VA_ARGS__ extension:

#define GET_MACRO(_0, _1, _2, NAME, ...) NAME #define FOO(...) GET_MACRO(_0, ##__VA_ARGS__, FOO2, FOO1, FOO0)(__VA_ARGS__) 

6 Comments

is it possible to allow FOO1 and FOO2 but not FOO0 without doing #define FOO0 _Pragma("error FOO0 not allowed")?
FOO0 not working in qt + mingw32, call FOO0 will invoke the FOO1
@leonp That's because ##__VA_ARGS__ is a GNU feature which differs from the C++11 standard. It works with -std=gnu++11.
Same problem if you're doing this in C and you try to use -std=c99 or -std=c11. You need to use -std=gnu99 or -std=gnu11 instead
It appears that replacing _0, ##__VA_ARGS__ with _0 __VA_OPT__(,) __VA_ARGS__ is the new way to do this.
|
57

Here is a more general solution:

// get number of arguments with __NARG__ #define __NARG__(...) __NARG_I_(__VA_ARGS__,__RSEQ_N()) #define __NARG_I_(...) __ARG_N(__VA_ARGS__) #define __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 __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 // general definition for any function name #define _VFUNC_(name, n) name##n #define _VFUNC(name, n) _VFUNC_(name, n) #define VFUNC(func, ...) _VFUNC(func, __NARG__(__VA_ARGS__)) (__VA_ARGS__) // definition for FOO #define FOO(...) VFUNC(FOO, __VA_ARGS__) 

Define your functions:

#define FOO2(x, y) ((x) + (y)) #define FOO3(x, y, z) ((x) + (y) + (z)) // it also works with C functions: int FOO4(int a, int b, int c, int d) { return a + b + c + d; } 

Now you can use FOO with 2, 3 and 4 arguments:

FOO(42, 42) // will use makro function FOO2 FOO(42, 42, 42) // will use makro function FOO3 FOO(42, 42, 42, 42) // will call FOO4 function 

Limitations

  • Only up to 63 arguments (but expandable)
  • Function for no argument only in GCC possible

Ideas

Use it for default arguments:

#define func(...) VFUNC(func, __VA_ARGS__) #define func2(a, b) func4(a, b, NULL, NULL) #define func3(a, b, c) func4(a, b, c, NULL) // real function: int func4(int a, int b, void* c, void* d) { /* ... */ } 

Use it for functions with possible infinite number of arguments:

#define SUM(...) VFUNC(SUM, __VA_ARGS__) #define SUM2(a, b) ((a) + (b)) #define SUM3(a, b, c) ((a) + (b) + (c)) #define SUM4(a, b, c) ((a) + (b) + (c) + (d)) // ... 

PS: __NARG__ is copied from Laurent Deniau & Roland Illig here: https://groups.google.com/group/comp.std.c/browse_thread/thread/77ee8c8f92e4a3fb/346fc464319b1ee5?pli=1

6 Comments

The macro __NARG_I_ seems completely unnecessary and superfluous. It just adds an extra step, and confusion. I recommend deleting it entirely and just defining __NARG__ instead as: #define __NARG__(...) __ARG_N(__VA_ARGS__,__RSEQ_N()).
Or will that somehow break pre-processing? Am I missing something?
Same with _VFUNC_: just delete it. Then, define _VFUNC as: #define _VFUNC(name, n) name##n instead of #define _VFUNC(name, n) _VFUNC_(name, n).
|
22

I was just researching this myself, and I came across this here. The author added default argument support for C functions via macros.

I'll try to briefly summarize the article. Basically, you need to define a macro that can count arguments. This macro will return 2, 1, 0, or whatever range of arguments it can support. Eg:

#define _ARG2(_0, _1, _2, ...) _2 #define NARG2(...) _ARG2(__VA_ARGS__, 2, 1, 0) 

With this, you need to create another macro that takes a variable number of arguments, counts the arguments, and calls the appropriate macro. I've taken your example macro and combined it with the article's example. I have FOO1 call function a() and FOO2 call function a with argument b (obviously, I'm assuming C++ here, but you can change the macro to whatever).

#define FOO1(a) a(); #define FOO2(a,b) a(b); #define _ARG2(_0, _1, _2, ...) _2 #define NARG2(...) _ARG2(__VA_ARGS__, 2, 1, 0) #define _ONE_OR_TWO_ARGS_1(a) FOO1(a) #define _ONE_OR_TWO_ARGS_2(a, b) FOO2(a,b) #define __ONE_OR_TWO_ARGS(N, ...) _ONE_OR_TWO_ARGS_ ## N (__VA_ARGS__) #define _ONE_OR_TWO_ARGS(N, ...) __ONE_OR_TWO_ARGS(N, __VA_ARGS__) #define FOO(...) _ONE_OR_TWO_ARGS(NARG2(__VA_ARGS__), __VA_ARGS__) 

So if you have

FOO(a) FOO(a,b) 

The preprocessor expands that to

a(); a(b); 

I would definitely read the article that I linked. It's very informative and he mentions that NARG2 won't work on empty arguments. He follows this up here.

Comments

12

Here is a more compact version of the answer above. With example.

#include <iostream> using namespace std; #define OVERLOADED_MACRO(M, ...) _OVR(M, _COUNT_ARGS(__VA_ARGS__)) (__VA_ARGS__) #define _OVR(macroName, number_of_args) _OVR_EXPAND(macroName, number_of_args) #define _OVR_EXPAND(macroName, number_of_args) macroName##number_of_args #define _COUNT_ARGS(...) _ARG_PATTERN_MATCH(__VA_ARGS__, 9,8,7,6,5,4,3,2,1) #define _ARG_PATTERN_MATCH(_1,_2,_3,_4,_5,_6,_7,_8,_9, N, ...) N //Example: #define ff(...) OVERLOADED_MACRO(ff, __VA_ARGS__) #define ii(...) OVERLOADED_MACRO(ii, __VA_ARGS__) #define ff3(c, a, b) for (int c = int(a); c < int(b); ++c) #define ff2(c, b) ff3(c, 0, b) #define ii2(a, b) ff3(i, a, b) #define ii1(n) ii2(0, n) int main() { ff (counter, 3, 5) cout << "counter = " << counter << endl; ff (abc, 4) cout << "abc = " << abc << endl; ii (3) cout << "i = " << i << endl; ii (100, 103) cout << "i = " << i << endl; return 0; } 

Run:

User@Table 13:06:16 /c/T $ g++ test_overloaded_macros.cpp User@Table 13:16:26 /c/T $ ./a.exe counter = 3 counter = 4 abc = 0 abc = 1 abc = 2 abc = 3 i = 0 i = 1 i = 2 i = 100 i = 101 i = 102 

Note that having both _OVR and _OVR_EXPAND may look redundant, but it's necessary for the preprocessor to expand the _COUNT_ARGS(__VA_ARGS__) part, which otherwise is treated as a string.

1 Comment

I like this solution. Can it be modified to handle an overloaded macro that takes zero arguments?
6

Here's a spin off from Evgeni Sergeev's answer. This one supports zero argument overloads as well!

I tested this with GCC and MinGW. It ought to work with old and new versions of C++. Note that I wouldn't guarantee it for MSVC... But with some tweaking, I'm confident it could be made to work with that too.

I also formatted this to be pasted into a header file (which I called macroutil.h). If you do that, you can just include this header whatever you need the feature, and not look at the nastiness involved in the implementation.

#ifndef MACROUTIL_H #define MACROUTIL_H //----------------------------------------------------------------------------- // OVERLOADED_MACRO // // used to create other macros with overloaded argument lists // // Example Use: // #define myMacro(...) OVERLOADED_MACRO( myMacro, __VA_ARGS__ ) // #define myMacro0() someFunc() // #define myMacro1( arg1 ) someFunc( arg1 ) // #define myMacro2( arg1, arg2 ) someFunc( arg1, arg2 ) // // myMacro(); // myMacro(1); // myMacro(1,2); // // Note the numerical suffix on the macro names, // which indicates the number of arguments. // That is the REQUIRED naming convention for your macros. // //----------------------------------------------------------------------------- // OVERLOADED_MACRO // derived from: https://stackoverflow.com/questions/11761703/overloading-macro-on-number-of-arguments // replaced use of _COUNT_ARGS macro with VA_NUM_ARGS defined below // to support of zero argument overloads #define OVERLOADED_MACRO(M, ...) _OVR(M, VA_NUM_ARGS(__VA_ARGS__)) (__VA_ARGS__) #define _OVR(macroName, number_of_args) _OVR_EXPAND(macroName, number_of_args) #define _OVR_EXPAND(macroName, number_of_args) macroName##number_of_args //#define _COUNT_ARGS(...) _ARG_PATTERN_MATCH(__VA_ARGS__, 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1) #define _ARG_PATTERN_MATCH(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15, N, ...) N // VA_NUM_ARGS // copied from comments section of: // http://efesx.com/2010/07/17/variadic-macro-to-count-number-of-arguments/ // which itself was derived from: // https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/ #define _ARG16(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, ...) _15 #define HAS_COMMA(...) _ARG16(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0) #define HAS_NO_COMMA(...) _ARG16(__VA_ARGS__, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1) #define _TRIGGER_PARENTHESIS_(...) , #define HAS_ZERO_OR_ONE_ARGS(...) \ _HAS_ZERO_OR_ONE_ARGS( \ /* test if there is just one argument, eventually an empty one */ \ HAS_COMMA(__VA_ARGS__), \ /* test if _TRIGGER_PARENTHESIS_ together with the argument adds a comma */ \ HAS_COMMA(_TRIGGER_PARENTHESIS_ __VA_ARGS__), \ /* test if the argument together with a parenthesis adds a comma */ \ HAS_COMMA(__VA_ARGS__ (~)), \ /* test if placing it between _TRIGGER_PARENTHESIS_ and the parenthesis adds a comma */ \ HAS_COMMA(_TRIGGER_PARENTHESIS_ __VA_ARGS__ (~)) \ ) #define PASTE5(_0, _1, _2, _3, _4) _0 ## _1 ## _2 ## _3 ## _4 #define _HAS_ZERO_OR_ONE_ARGS(_0, _1, _2, _3) HAS_NO_COMMA(PASTE5(_IS_EMPTY_CASE_, _0, _1, _2, _3)) #define _IS_EMPTY_CASE_0001 , #define _VA0(...) HAS_ZERO_OR_ONE_ARGS(__VA_ARGS__) #define _VA1(...) HAS_ZERO_OR_ONE_ARGS(__VA_ARGS__) #define _VA2(...) 2 #define _VA3(...) 3 #define _VA4(...) 4 #define _VA5(...) 5 #define _VA6(...) 6 #define _VA7(...) 7 #define _VA8(...) 8 #define _VA9(...) 9 #define _VA10(...) 10 #define _VA11(...) 11 #define _VA12(...) 12 #define _VA13(...) 13 #define _VA14(...) 14 #define _VA15(...) 15 #define _VA16(...) 16 #define VA_NUM_ARGS(...) VA_NUM_ARGS_IMPL(__VA_ARGS__, PP_RSEQ_N(__VA_ARGS__) ) #define VA_NUM_ARGS_IMPL(...) VA_NUM_ARGS_N(__VA_ARGS__) #define VA_NUM_ARGS_N( \ _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \ _11,_12,_13,_14,_15,_16,N,...) N #define PP_RSEQ_N(...) \ _VA16(__VA_ARGS__),_VA15(__VA_ARGS__),_VA14(__VA_ARGS__),_VA13(__VA_ARGS__), \ _VA12(__VA_ARGS__),_VA11(__VA_ARGS__),_VA10(__VA_ARGS__), _VA9(__VA_ARGS__), \ _VA8(__VA_ARGS__),_VA7(__VA_ARGS__),_VA6(__VA_ARGS__),_VA5(__VA_ARGS__), \ _VA4(__VA_ARGS__),_VA3(__VA_ARGS__),_VA2(__VA_ARGS__),_VA1(__VA_ARGS__), \ _VA0(__VA_ARGS__) //----------------------------------------------------------------------------- #endif // MACROUTIL_H 

Comments

6

Based on @netcoder's answer and @vexe's suggestion about the Visual Studio compiler support, I found this code working pretty well across various platforms:

#define FOO1(a) func1(a) #define FOO2(a, b) func2(a, b) #define FOO3(a, b, c) func3(a, b, c) #define EXPAND(x) x #define GET_MACRO(_1, _2, _3, NAME, ...) NAME #define FOO(...) EXPAND(GET_MACRO(__VA_ARGS__, FOO3, FOO2, FOO1)(__VA_ARGS__)) 

, where func1(), func2(), func3() are just normal functions that accept different number of parameters.

Comments

4

This seems to work fine on GCC, Clang and MSVC. It's a cleaned up version of some of the answers here

#define _my_BUGFX(x) x #define _my_NARG2(...) _my_BUGFX(_my_NARG1(__VA_ARGS__,_my_RSEQN())) #define _my_NARG1(...) _my_BUGFX(_my_ARGSN(__VA_ARGS__)) #define _my_ARGSN(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,N,...) N #define _my_RSEQN() 10,9,8,7,6,5,4,3,2,1,0 #define _my_FUNC2(name,n) name ## n #define _my_FUNC1(name,n) _my_FUNC2(name,n) #define GET_MACRO(func,...) _my_FUNC1(func,_my_BUGFX(_my_NARG2(__VA_ARGS__))) (__VA_ARGS__) #define FOO(...) GET_MACRO(FOO,__VA_ARGS__) 

1 Comment

@RianQuinn How to adjust this macro so that it works with zero argument #define func0() foo? The current version does not handle this case unfortunately.
3

Maybe you can use this macro to count the number of arguments.

#define VA_NUM_ARGS(...) VA_NUM_ARGS_IMPL(__VA_ARGS__, 5,4,3,2,1) #define VA_NUM_ARGS_IMPL(_1,_2,_3,_4,_5,N,...) N 

Comments

1

Based on R1tschY's reply, here's what I did to implement variable arguments and default arguments, using the Deniau-Illig construction.

// ---------------------------------------------------------------- // library #define __nargs100__(a00,a01,a02,a03,a04,a05,a06,a07,a08,a09,a0a,a0b,a0c,a0d,a0e,a0f,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a1a,a1b,a1c,a1d,a1e,a1f,a20,a21,a22,a23,a24,a25,a26,a27,a28,a29,a2a,a2b,a2c,a2d,a2e,a2f,a30,a31,a32,a33,a34,a35,a36,a37,a38,a39,a3a,a3b,a3c,a3d,a3e,a3f,a40,a41,a42,a43,a44,a45,a46,a47,a48,a49,a4a,a4b,a4c,a4d,a4e,a4f,a50,a51,a52,a53,a54,a55,a56,a57,a58,a59,a5a,a5b,a5c,a5d,a5e,a5f,a60,a61,a62,a63,a64,a65,a66,a67,a68,a69,a6a,a6b,a6c,a6d,a6e,a6f,a70,a71,a72,a73,a74,a75,a76,a77,a78,a79,a7a,a7b,a7c,a7d,a7e,a7f,a80,a81,a82,a83,a84,a85,a86,a87,a88,a89,a8a,a8b,a8c,a8d,a8e,a8f,a90,a91,a92,a93,a94,a95,a96,a97,a98,a99,a9a,a9b,a9c,a9d,a9e,a9f,aa0,aa1,aa2,aa3,aa4,aa5,aa6,aa7,aa8,aa9,aaa,aab,aac,aad,aae,aaf,ab0,ab1,ab2,ab3,ab4,ab5,ab6,ab7,ab8,ab9,aba,abb,abc,abd,abe,abf,ac0,ac1,ac2,ac3,ac4,ac5,ac6,ac7,ac8,ac9,aca,acb,acc,acd,ace,acf,ad0,ad1,ad2,ad3,ad4,ad5,ad6,ad7,ad8,ad9,ada,adb,adc,add,ade,adf,ae0,ae1,ae2,ae3,ae4,ae5,ae6,ae7,ae8,ae9,aea,aeb,aec,aed,aee,aef,af0,af1,af2,af3,af4,af5,af6,af7,af8,af9,afa,afb,afc,afd,afe,aff,a100,...) a100 #define __nargs__(...) __nargs100__(,##__VA_ARGS__, ff,fe,fd,fc,fb,fa,f9,f8,f7,f6,f5,f4,f3,f2,f1,f0,ef,ee,ed,ec,eb,ea,e9,e8,e7,e6,e5,e4,e3,e2,e1,e0,df,de,dd,dc,db,da,d9,d8,d7,d6,d5,d4,d3,d2,d1,d0,cf,ce,cd,cc,cb,ca,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0,bf,be,bd,bc,bb,ba,b9,b8,b7,b6,b5,b4,b3,b2,b1,b0,af,ae,ad,ac,ab,aa,a9,a8,a7,a6,a5,a4,a3,a2,a1,a0,9f,9e,9d,9c,9b,9a,99,98,97,96,95,94,93,92,91,90,8f,8e,8d,8c,8b,8a,89,88,87,86,85,84,83,82,81,80,7f,7e,7d,7c,7b,7a,79,78,77,76,75,74,73,72,71,70,6f,6e,6d,6c,6b,6a,69,68,67,66,65,64,63,62,61,60,5f,5e,5d,5c,5b,5a,59,58,57,56,55,54,53,52,51,50,4f,4e,4d,4c,4b,4a,49,48,47,46,45,44,43,42,41,40,3f,3e,3d,3c,3b,3a,39,38,37,36,35,34,33,32,31,30,2f,2e,2d,2c,2b,2a,29,28,27,26,25,24,23,22,21,20,1f,1e,1d,1c,1b,1a,19,18,17,16,15,14,13,12,11,10,f,e,d,c,b,a,9,8,7,6,5,4,3,2,1,0) #define __vfn(name, n) name##n #define _vfn( name, n) __vfn(name, n) #define vfn( fn, ...) _vfn(fn, __nargs__(__VA_ARGS__))(__VA_ARGS__) // ---------------------------------------------------------------- // example // backend: actual implementation, 2 mandatory args, 3 optional args #define _bshow(bdim,data, ncols,nbits,base)({ \ /* do stuff here */ \ }) // "frontend", default arguments get implemented here. the suffix is the number of arguments, in hexadecimal base #define bshow2(...) _bshow(__VA_ARGS__, 16,32,16) #define bshow3(...) _bshow(__VA_ARGS__, 32,16) #define bshow4(...) _bshow(__VA_ARGS__, 16) #define bshow5(...) _bshow(__VA_ARGS__) #define bshow(...) vfn(bshow,__VA_ARGS__) // test bshow(0x100,data0); bshow(0x100,data0, 14); bshow(0x100,data0, 12,16); bshow(0x100,data0, 10, 8,2); 

Comments

0

I came up with a generic solution by myself. Though it is a little verbose, it supports default overload, and provides a template to create any overloading macro as long as it needs.

#define GET_OVERLOAD_RESULT_( \ _0, _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, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, \ _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, \ _92, _93, _94, _95, _96, _97, _98, _99, _100, result, ...) \ result #define OVERLOADER_TAKES_AT_MOST_100_ARGS_(func, ...) \ GET_OVERLOAD_RESULT_( \ __VA_ARGS__, func(100), func(99), func(98), func(97), func(96), \ func(95), func(94), func(93), func(92), func(91), func(90), func(89), \ func(88), func(87), func(86), func(85), func(84), func(83), func(82), \ func(81), func(80), func(79), func(78), func(77), func(76), func(75), \ func(74), func(73), func(72), func(71), func(70), func(69), func(68), \ func(67), func(66), func(65), func(64), func(63), func(62), func(61), \ func(60), func(59), func(58), func(57), func(56), func(55), func(54), \ func(53), func(52), func(51), func(50), func(49), func(48), func(47), \ func(46), func(45), func(44), func(43), func(42), func(41), func(40), \ func(39), func(38), func(37), func(36), func(35), func(34), func(33), \ func(32), func(31), func(30), func(29), func(28), func(27), func(26), \ func(25), func(24), func(23), func(22), func(21), func(20), func(19), \ func(18), func(17), func(16), func(15), func(14), func(13), func(12), \ func(11), func(10), func(9), func(8), func(7), func(6), func(5), \ func(4), func(3), func(2), func(1), func(0)) #define GET_ARGS_COUNT_(n) n #define ARGS_COUNT(...) \ OVERLOADER_TAKES_AT_MOST_100_ARGS_(GET_ARGS_COUNT_, _, ##__VA_ARGS__) #define CONCAT_TOKEN(a, ...) a##__VA_ARGS__ #define CHOOSE_OVERLOAD_(_, overload, ...) overload #define DISPATCH_OVERLOAD_INTERNAL_(default_overload, ...) \ CHOOSE_OVERLOAD_(__VA_ARGS__, default_overload) #define DISPATCH_OVERLOAD(overload_func, n) \ DISPATCH_OVERLOAD_INTERNAL_(overload_func##_default, \ CONCAT_TOKEN(overload_func##_, n)) #define MAKE_OVERLOAD(func) _, func #define DEFINE_OVERLOAD_MACRO(overloader, ...) \ OVERLOADER_TAKES_AT_MOST_100_ARGS_(overloader, _, ##__VA_ARGS__)(__VA_ARGS__) 

ARGS_COUNT is used to determine the number of the arguments it takes. And there are several macro for creating a custom overload. For example:

template <typename... Args> std::string default_printer(Args&&... args) { return "default"; } #define PRINT_1_arg(a) ("print one argument. " #a ": " + std::to_string(a)) #define PRINT_2_args(a, b) \ ("print two arguments. " #a ": " + std::to_string(a) + ", " #b ": " + std::to_string(b)) // define the overload of one argument #define PRINT_IMPL_1 MAKE_OVERLOAD(PRINT_1_arg) // define the overload of two arguments #define PRINT_IMPL_2 MAKE_OVERLOAD(PRINT_2_args) // define the default overload #define PRINT_IMPL_default(...) default_printer(__VA_ARGS__) // define a helper (I hope it can be ommited, yet I didn't find a way so far) #define PRINT_OVERLOADER(n) DISPATCH_OVERLOAD(PRINT_IMPL, n) // the custom overload macro is named `PRINT` #define PRINT(...) DEFINE_OVERLOAD_MACRO(PRINT_OVERLOADER, ##__VA_ARGS__) int main() { int a = 0; double b = 1.5; std::string c = "234"; static_assert(ARGS_COUNT() == 0); static_assert(ARGS_COUNT(a) == 1); static_assert(ARGS_COUNT(a, b) == 2); static_assert(ARGS_COUNT(a, b, c) == 3); // the output of following codes is: // default // print one argument. a: 0 // print two arguments. a: 0, b: 1.500000 // default std::cout << PRINT() << '\n'; std::cout << PRINT(a) << '\n'; std::cout << PRINT(a, b) << '\n'; std::cout << PRINT(a, b, c) << '\n'; } 

1 Comment

warning: this solution only works with compiler supporting the ##__VA_ARGS__ extension

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.