我有两个宏FOO2和FOO3:

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

我想定义一个新的宏FOO如下所示:

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

但这是行不通的,因为宏不会重载参数的数量。

在不修改FOO2和FOO3的情况下,是否有某种方法来定义一个宏FOO(使用__VA_ARGS__或其他方式)来获得将FOO(x,y)分配给FOO2和将FOO(x,y,z)分配给FOO3的相同效果?


当前回答

简单:

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

所以如果你有这些宏,它们会像描述的那样展开:

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)          // expands to FOO4(a,b,c,d)

当然,如果定义了FOO2、FOO3和FOO4,输出将被已定义宏的输出所取代。

其他回答

为了补充netcoder的答案,你实际上可以用一个0参数宏来做这个,在GCC ##__VA_ARGS__扩展的帮助下:

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

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

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

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

#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

根据@netcoder的回答和@vexe关于Visual Studio编译器支持的建议,我发现这段代码在各种平台上都运行得很好:

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

,其中func1(), func2(), func3()只是普通函数,接受不同数量的形参。

我自己也在研究这个,我在这里发现了这个。作者通过宏为C函数添加了默认参数支持。

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

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

因此,您需要创建另一个宏,该宏接受可变数量的参数,计算参数,并调用适当的宏。我使用了您的示例宏,并将其与本文的示例结合起来。我有FOO1调用函数a()和FOO2调用函数a与参数b(显然,我在这里假设c++,但你可以改变宏为任何)。

#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不会对空洞的论点起作用。他顺着这个往上走。