假设我在C++标头中定义了一个类似如下的函数:
namespace foo {
void bar(int a, int b = 1);
}
我想在C代码中使用这个函数。一个显而易见的解决方案是定义两个函数,如下所示:
void foo_bar_1(int a)
{ foo::bar(a, 1); }
void foo_bar_2(int a, int b)
{ foo::bar(a, b); }
然后,这些代码就可以轻松地包含在C代码中。然而,对于多个默认参数来说,这会变得很糟糕,有一个包装器函数会更好。我想做这样的事情:
#define _test_foo_numargs(...) (sizeof((int[]){__VA_ARGS__})/sizeof(int))
#define test_foo(...) do { \
if (_test_foo_numargs(__VA_ARGS__) == 1) \
test_foo_1(__VA_ARGS__); \
else if (_test_foo_numargs(__VA_ARGS__) == 2) \
test_foo_2(__VA_ARGS__); \
} while (0)
但这不起作用,因为对test_foo_1
和test_foo_2
的两个调用都必须是有效的,才能进行编译。
有没有更好的方法来做这件事?
发布于 2020-12-27 18:13:00
您可以执行以下操作:
#define TAKE_9(_1, _2, _3, _4, _5, _6, _7, _8, _9, ...) _9
#define COUNT(...) TAKE_9(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1)
#define CONCAT_(A, B) A ## B
#define CONCAT(A, B) CONCAT_(A, B)
#define SELECT(NAME, ...) CONCAT(NAME, COUNT(__VA_ARGS__))(__VA_ARGS__)
#define foo_bar(...) SELECT(foo_bar_, __VA_ARGS__)
Demo
如果您的编译器支持COUNT
,则可以升级它来处理0
参数
#define COUNT(...) TAKE_9(__VA_ARGS__ __VA_OPT__(,) 8, 7, 6, 5, 4, 3, 2, 1, 0)
Demo
为了避免不得不编写foo_bar_N
,您可以这样做:
// ...
#define FUNC_WITH_DEFAULT_ARG_2(func, DEFAULT, ...) TAKE_3(__VA_ARGS__ __VA_OPT__(,) \
func(__VA_ARGS__), \
func(__VA_ARGS__, TAKE_2 DEFAULT), \
func(TAKE_1 DEFAULT, TAKE_2 DEFAULT) )
#define FUNC_WITH_DEFAULT_ARG_3(func, DEFAULT, ...) TAKE_4(__VA_ARGS__ __VA_OPT__(,) \
func(__VA_ARGS__), \
func(__VA_ARGS__, TAKE_2 DEFAULT), \
func(__VA_ARGS__, TAKE_2 DEFAULT, TAKE_3 DEFAULT), \
func(TAKE_1 DEFAULT, TAKE_2 DEFAULT, TAKE_3 DEFAULT) )
// Choose on or other, error message for misuse might differ
// RequiredParameter is just a name for "better" error message when not enough parameter are given
#define foo_bar(...) FUNC_WITH_DEFAULT_ARG_2(foo_bar_impl, (RequiredParameter, 1), __VA_ARGS__)
#define foo_bar2(_1, ...) FUNC_WITH_DEFAULT_ARG_3(foo_bar_impl, (_1, 0), __VA_ARGS__)
void foo_bar_impl(int a, int b)
{ foo::bar(a, b); }
Demo
https://stackoverflow.com/questions/65464272
复制相似问题