在参数数量上重载macros

我有两个macrosFOO2FOO3

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

我想要定义一个新的macrosFOO ,如下所示:

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

但是这不起作用,因为macros不会超过参数的数量。

在没有修改FOO2FOO3 ,是否有某种方法来定义macrosFOO (使用__VA_ARGS__或其他方法)以获得将FOO(x,y)分配到FOO2FOO(x,y,z)FOO3的相同效果?

简单如:

 #define GET_MACRO(_1,_2,_3,NAME,...) NAME #define FOO(...) GET_MACRO(__VA_ARGS__, FOO3, FOO2)(__VA_ARGS__) 

所以如果你有这些macros:

 FOO(World, !) # expands to FOO2(World, !) FOO(foo,bar,baz) # expands to FOO3(foo,bar,baz) 

如果你想要第四个:

 #define GET_MACRO(_1,_2,_3,_4,NAME,...) NAME #define FOO(...) GET_MACRO(__VA_ARGS__, FOO4, FOO3, FOO2)(__VA_ARGS__) FOO(a,b,c,d) # expeands to FOO4(a,b,c,d) 

当然,如果你定义了FOO2FOO3FOO4 ,输出将被定义的macros替代。

要添加到netcoder的答案 ,你可以用一个0参数macros来实现这一点,在GCC ##__VA_ARGS__扩展的帮助下:

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

这是一个更一般的解决scheme:

 // 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__) 

定义你的function:

 #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; } 

现在你可以用2,3和4个参数来使用FOO

 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 

限制

  • 只有多达63个参数(但可扩展)
  • 只有在GCC可能的情况下,没有参数的函数

思路

将其用于默认参数:

 #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) { /* ... */ } 

将其用于可能有无数个参数的函数:

 #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__复制自: https : __NARG__ = 1

我只是在研究这个,我在这里遇到了 。 作者通过macros添加了C函数的默认参数支持。

我会尽量简要地总结一下这篇文章。 基本上,你需要定义一个可以计算参数的macros。 这个macros将返回2,1,0,或任何它可以支持的参数范围。 例如:

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

有了这个,你需要创build另一个macros,这个macros需要可变数量的参数,对参数进行计数,并调用相应的macros。 我已经把你的例子macros,并结合文章的例子。 我有FOO1调用函数a()和FOO2调用函数a与参数b(显然,我假设C ++在这里,但您可以将macros更改为任何)。

 #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__) 

所以,如果你有

 FOO(a) FOO(a,b) 

预处理器扩展到

 a(); a(b); 

我肯定会阅读我链接的文章。 这是非常翔实的,他提到NARG2将不会工作在空的论据。 他在这里继续 。

也许你可以使用这个macros来计算参数的数量 。

 #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 

这是上面答案的一个更紧凑的版本。 用例子。

 #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; } 

跑:

 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 

请注意,同时具有_OVR_OVR_EXPAND可能看起来多余,但预处理器需要扩展_COUNT_ARGS(__VA_ARGS__)部分,否则将被视为string。

这似乎在GCC,Clang和MSVC上工作得很好。 这是这里一些答案的清理版本

 #define __BUGFX(x) x #define __NARG2(...) __BUGFX(__NARG1(__VA_ARGS__,__RSEQN())) #define __NARG1(...) __BUGFX(__ARGSN(__VA_ARGS__)) #define __ARGSN(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,N,...) N #define __RSEQN() 10,9,8,7,6,5,4,3,2,1,0 #define __FUNC2(name,n) name ## n #define __FUNC1(name,n) __FUNC2(name,n) #define GET_MACRO(func,...) __FUNC1(func,__BUGFX(__NARG2(__VA_ARGS__))) (__VA_ARGS__)