[英]Wrap C++ function with default parameters in C
假設我有一個像這樣定義在 C++ header 中的 function:
namespace foo {
void bar(int a, int b = 1);
}
我想在 C 代碼中使用這個 function。 一個明顯的解決方案是定義兩個這樣的函數:
void foo_bar_1(int a)
{ foo::bar(a, 1); }
void foo_bar_2(int a, int b)
{ foo::bar(a, b); }
這些可以很容易地包含在 C 代碼中。 然而,這對於多個默認參數來說變得很難看,最好有一個包裝器 function。 我想過做這樣的事情:
#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
的調用都必須有效才能編譯。
有一個更好的方法嗎?
我將在這里提供我自己的解決方案,以防沒有人有更好的解決方案並且將來有人遇到同樣的問題:
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
int _test_foo_1(int a)
{ return a; }
int _test_foo_2(int a, int b)
{ return a + b; }
int _test_foo_va(size_t num_args, ...)
{
va_list args;
va_start(args, num_args);
switch (num_args) {
case 1:
return _test_foo_1(va_arg(args, int));
case 2:
return _test_foo_2(va_arg(args, int), va_arg(args, int));
}
va_end(args);
}
#define _test_foo_numargs(...) (sizeof((int[]){__VA_ARGS__})/sizeof(int))
#define test_foo(...) _test_foo_va(_test_foo_numargs(__VA_ARGS__), __VA_ARGS__)
int main()
{
printf("%d\n", test_foo(1));
printf("%d\n", test_foo(1, 2));
}
這當然是非常不安全的,因為如果傳遞的 arguments 太少或太多,它將編譯。
您可以執行以下操作:
#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__)
COUNT
可以升級到處理0
arguments,如果你的編譯器支持它
#define COUNT(...) TAKE_9(__VA_ARGS__ __VA_OPT__(,) 8, 7, 6, 5, 4, 3, 2, 1, 0)
為了避免不得不寫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); }
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.