使常规函数用模板包装成员函数

Making a regular function wrap a member function with templates

我正在使用一个具有 C API 的框架,其 typedef 看起来像这样:

typedef int (*function_type)(int argc, voidptr_t args[], void *data)

和一个采用此类函数指针的函数,如下所示:

void create_callback(function_type fn, void *data);

(如果不是很明显,voidptr_t 只是 void * 的另一个类型定义)

框架将根据需要在特定时间调用回调,并设置 argc 和 args 参数以反映当时有效的条件。 argc 永远不会小于 1,并且 args 中的第一个条目将始终是指向某些有效数据的指针,这些数据可以转换为指向我程序中某些 class 的指针,并且可以在许多方面被认为是'this' 指针,因为它指示回调预期作用或使用的对象或数据。

我将从 C++ 中调用此 API,并且我想要一种方法来包装 classes 的成员函数,如下所示:

class A
{
    int member_fn1(int argc, voidptr_t args[], void *data);
};

class B
{
    int member_fn2(int argc, voidptr_t args[], void *data);
};

现在我想要一种将这些成员函数用作回调的方法....我可以通过更改 A 和 B 的定义来包括我可以用作回调的静态函数来实现,如下所示:

class A
{
    int member_fn1(int argc, voidptr_t args[], void *data);
    static int call_fn1(int argc, voidptr_t args[], void *data)
    {
       ((A*)args[0])->*fn1(argc-1,&args[1],dat
    }
};

class B
{
    int member_fn2(int argc, voidptr_t args[], void *data);
    static int call_fn2(int argc, voidptr_t args[], void *data)
    {
       ((B*)args[0])->fn2(argc-1,&args[1],data);
    }
};

但是,如果我必须为每个我想用作回调的成员函数定义一个附加的静态函数,这将变得非常乏味。但是,正如您从中看到的那样,我们的想法是仅将其他参数传递给成员函数,并允许第一个参数采用 this.

的值

我想要做的是定义某种模板函数,我可以将其作为参数传递给 create_callback,并将包装一个成员函数,以便它可以作为回调调用。

wrap_function 看起来像这样:

template<????> int wrap_function(int argc, voidptr_t args[], void *data)
{
   try {
      return ((X*)args[0])->fn(argc-1, &args[1], data);
   } catch(...) {
      // handle any exception safely, because we can't let it get back into C code
      handle_exception(std::current_exception());
      return -1
   }
}

其中 X 是 class 的类型名称,fn 是成员函数本身。

请注意,此函数还可以灵活地处理异常,否则我会为我想用作回调的每个成员函数一遍又一遍地编写几乎相同的代码...这就是我要设置它的原因作为模板函数。

所以一旦我定义了 wrap_function,我就可以通过这样做在 API 中定义回调:

create_callback(wrap_function<&A::member_function1>, some_data)
create_callback(wrap_function<&B::member_function2>, some_other_data)

由于 wrap_function 的定义只是一个常规函数而不是方法,我可以将其地址作为常规函数指针传递给 C API,函数的职责将是将其工作委托给正确的 class.

中正确的成员函数

但是我该如何准确地定义 wrap_function 模板才能使其正常工作?

我真诚地希望这个问题能够清楚...如果有人觉得它需要描述得更好,请在评论中具体指出下面不清楚的地方,以便我改进这个问题。

template <typename X, int (X::*fn)(int, voidptr_t[], void*)>
int wrap_function(int argc, voidptr_t args[], void *data) {
  return (static_cast<X*>(args[0])->*fn)(argc-1, &args[1], data);
}

我认为应该可以。你这样使用它:

create_callback(wrap_function<A, &A::member_function1>, some_data)