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

Making a regular function wrap a member function with templates

本文关键字:函数 包装 成员 常规      更新时间:2023-10-16

我正在使用一个框架,该框架具有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 的另一个 typedef *)

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

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

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是类的类型名,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,并且函数的职责是将其工作委托给正确类中的正确成员函数。

但是,我如何准确定义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)