简体   繁体   中英

Writing a generalized wrapper for different functions with variable number of arguments

I want to write a C++ wrapper for a bunch of functions which are all similar in what they do. But they all have a different number of arguments. For example (assume typeA, typeB, etc. are different typedef'd types):

typeA func1 (typeB b, typeC c);

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

These are the functions I want to write a wrapper for (notice that both have return type typeA and first argument of type typeB). So I intend to create a general wrapper class and store a list of arguments in the constructor. And I want to be able to call a function which looks like 'func' in the following:

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);
}

So, I want to write func in such a way that it calls whatever function (either func1 or func2) with the arguments passed into the constructor.

I want to know if there is a way I can treat func1 or func2 as though they have a variable number of arguments. Or at least, if there is a way in C++ in which I can feed in a function and a list of arguments and get eval (function, argument_list).

The alternative is writing a wrapper for every single function, which I want to avoid but am not averse to. (Also, I don't mind if a solution involves me not using a wrapper class but a wrapper function)

Here is something I have done in C, to wrap around any function. I hope it will help/inspire you. The main restriction is that you can wrap only around user defined functions, since you will have to modify the signature of the function.

My solution uses the va_arg structure.

#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
}

The signature of the wrapper takes the pointer to the function you want to execute, a pointer to give to the function to retrieve your return value, the number of arguments of youe call to the function, and then the arguments of the function you want to call.

The va_list is a list of arguments. You initialize it with va_start. The first argument of va_start is the va_list you want to initialize. The second argument is the last known parameter of the current function (in this example, it's 'n').

Now, instead of the ellipsis in your user defined function, you will put an argument va_list.

Two examples I had:

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);
}

I managed to use the same wrapper to call this two different functions with some modifications in the signature and in the function bodies. The thing is that in arguments and in returns, I only give pointers. So I have to dereference the pointers.

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;
}

Now I am able to use the same wrapper function in my main to call these two functions:

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);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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