繁体   English   中英

用 C 中的默认参数包装 C++ function

[英]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_1test_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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM