使用可变数量的参数为不同函数编写通用包装器

时间:2012-07-21 06:32:45

标签: c++ wrapper variadic-functions

我想为一堆函数编写一个C ++包装器,它们的功能都很相似。但他们都有不同的论点。例如(假设typeA,typeB等是不同的typedef类型):

typeA func1 (typeB b, typeC c);

typeA func2 (typeB b, typeD d, typeE e);

这些是我想要编写包装器的函数(注意两者都有返回类型typeA和类型为typeB的第一个参数)。所以我打算创建一个通用的包装类并在构造函数中存储一个参数列表。我希望能够在下面调用一个看起来像'func'的函数:

class wrapper {
  public:
    wrapper (/*args - a list of arguments, including 
               a pointer to the actual function, and 
               the remaining arguments depending 
               on the function. */);
    void func (typeB b, typeA &a);
}

所以,我想用这样的方式编写func,它调用任何函数(func1或func2)和传递给构造函数的参数。

我想知道是否有一种方法可以将func1或func2视为具有可变数量的参数。或者至少,如果在C ++中有一种方法可以在函数和参数列表中输入并获得eval(function,argument_list)。

替代方法是为每个函数编写一个包装器,我想避免但不反对。 (另外,我不介意解决方案是否涉及我不使用包装类而是使用包装函数)

1 个答案:

答案 0 :(得分:0)

这是我在C中所做的事情,以包装任何函数。我希望它能帮助/激励你。 主要的限制是你只能包装用户定义的函数,因为你必须修改函数的签名。

我的解决方案使用va_arg结构。

#include <stdarg.h>
void * super_wrapper( void * (*fn)(), void * ret, int n, ...)
{
  va_list = my_list;
  va_start(my_list, n);
  ret = (*fn)(ret, n, my_list);
  va_end(my_list);
  return ret
}

包装器的签名采用指向要执行的函数的指针,指向函数的指针以检索返回值,调用函数的参数个数,然后是函数的参数你想打电话。

va_list是一个参数列表。 用va_start初始化它。 va_start的第一个参数是您要初始化的va_list。第二个参数是当前函数的最后一个已知参数(在本例中,它是'n')。

现在,您将使用参数va_list而不是用户定义函数中的省略号。

我有两个例子:

double sum (int n, ...)
{
  int i;
  double res = 0;
  double tmp;
  va_list = my_list;
  va_start(my_list, n);
  for(i=0; i<n; i++)
  {
    tmp = va_arg(my_list, double);
    res += tmp;
  }
  va_end(my_list);
  return res;
}

void my_print(int n, ...)
{
  int i;
  va_list my_list;
  va_start(my_list, n);
  char * tmp;
  for(i=0; i<n; i++)
  {
    tmp = va_arg(my_list, char *);
    printf("%s ", tmp);
  }
  printf("\n");
  va_end(my_list);
}

我设法使用相同的包装器来调用这两个不同的函数,并在签名和函数体中进行一些修改。 问题是在论证和回报中,我只是指点。所以我必须取消引用指针。

void * sum (void * ret, int n, va_list my_list)
{
  int i;
  double res = 0;
  double *tmp;
  for(i=0; i<n; i++)
  {
    tmp = va_arg(my_list, double);
    res += *tmp;
  }
  ret = &res;
  return ret;
}

void* my_print(int n, ...)
{
  int i;
  char ** tmp;
  for(i=0; i<n; i++)
  {
    tmp = va_arg(my_list, char **);
    printf("%s ", *tmp);
  }
  printf("\n");
  return ret;
}

现在我可以在main中使用相同的包装函数来调用这两个函数:

void main()
{
  double two = 2.0;
  double three = 3.0;
  double fifteen = 15.0;

  char *I, *am, *a, *great, *wrapper;
  I = malloc(sizeof(char) * 2);
  am = malloc(sizeof(char) * 3);
  a = malloc(sizeof(char)*2);
  great = malloc(sizeof(char) * 6;
  wrapper = malloc(sizeof(char) * 8);

  I = strcpy(I, "I\0");
  am = strcpy(am, "am\0");
  a = strcpy(a,"a\0");
  great = strcpy(great, "great\0");
  wrapper = strcpy(wrapper, "wrapper\0");

  void * ret;

  printf("Sum = %f\n", *( (double*)super_wrapper(sum, ret, 3, &two, &three, &fifteen) ) );
  super_wrapper(my_print, ret, 5, &I, &am, &a, &great, &wrapper);
}