将参数中的静态函数指针替换为实例中方法的指针

Replacing static function pointer in argument by a pointer to a method in instance

本文关键字:指针 方法 实例 静态函数 参数 替换      更新时间:2023-10-16

我使用第三方库,该库要求将指向静态函数的指针作为回调参数传递。现在我必须做这样的事情:

static int MyCallback( ...)
{
    // Callback code here...
}
int main( int argc, char* argv[])
{
    ThirdPartyFunction( &MyCallback, ... );
}

我想做的是用C++类实例的成员方法替换我必须提供的静态回调函数。类似这样的东西:

class MyClass
{
public:
    int MyCallbackMethod( ... );
};
int main(int argc, char* argv[])
{
    MyClass instanceOfMyClass;
    ThirdPartyFunction( &(????), ... );
}

我的问题是,当我将&instanceOfMyClass::MyCallbackMethod传递给ThirdPartyFunction()时,它不会编译。当启动一个线程(比如,std::thread)时,会传递(&MyClass::MyCallbackMethod, this),但在这种情况下,ThirdPartyFunction(似乎是用C而不是C++编写的)不允许我传递函数指针和拥有该方法的对象。

另一方面,如果我在MyClass中声明static int MyCallbackMethod,它当然有效,但我没有实例,这不是我想要的。

我的问题很简单:是否可以传递类似(&MyClass::MyCallbackMethod, this)实例方法)的东西来代替&MyClass::MyCallbackMethodstatic方法++11。

提前感谢您的帮助!

编辑1

我使用libmicrohttpd(请参阅microhttpd.h)

功能"ThirdPartyFunction":

_MHD_EXTERN struct MHD_Daemon *
MHD_start_daemon_va (unsigned int flags,
         uint16_t port,
         MHD_AcceptPolicyCallback apc, void *apc_cls,
         MHD_AccessHandlerCallback dh, void *dh_cls,
         va_list ap);

例如,MHD_AcessHandlerCallback被声明为:

typedef int
(*MHD_AccessHandlerCallback) (void *cls,
                          struct MHD_Connection *connection,
                          const char *url,
                          const char *method,
                          const char *version,
                          const char *upload_data,
                          size_t *upload_data_size,
                          void **con_cls);

所以我必须使用一个有这个签名的函数。我想在实例方法而不是静态函数上使用相同的签名。

如果ThirdPartyFunction是在C中定义的,那么它不可能以这样的方式声明,即您可以将非静态成员函数传递给它。

只能将正则函数绑定到正则函数指针。因此,编写一个包装函数,它不是调用该成员函数的非静态成员。但是如何获得一个实例来调用非静态成员呢?

C Api可能允许您传递指向将传递给回调的任意数据的void*。如果是,则可以将对象实例作为任意数据传递。

如果没有,那么您可以使用静态实例或指向实例的静态指针,但这些可能会很有问题,因为这会使回调在静态初始化期间不可用,并且使其不可重入,这也会使其在多线程上下文中不可用。


根据您的编辑更新:

您的API确实支持将void*数据传递给回调(两个回调),因此我建议您使用它。

* @param apc callback ...
* @param apc_cls extra argument to apc

不能传递指向成员函数的指针来代替指向非成员或静态成员函数的指示器,因为成员函数需要调用它们的对象。指向该对象的指针将成为成员函数的隐式this参数。

如果需要将调用分派给成员函数,则需要有一种方法来查找调用该函数的对象。这里有两种通用方法:

  • 将指向对象的对象指针放在程序已知的某个位置。传递一个静态函数来查找对象目标,并对其调用回调
  • 依赖API功能,该功能允许您将"用户数据"传递到回调,并在回调中放置对象指针

在这两种情况下,都将静态或非成员函数注册为第三方API的回调函数。

以下是第一种方法的示例:

struct MyClass {
    int MyCallbackMethod( ... );
};
static MyClass *instancePointer;
static int MyStaticCallback( ...) {
    instancePointer->MyCallbackMethod(...);
}
int main(int argc, char* argv[]) {
    MyClass instanceOfMyClass;
    // Point instancePointer to instanceOfMyClass for the static callbacl
    instancePointer = &instanceOfMyClass;
    // Register static callback
    ThirdPartyFunction( &MyStaticCallback, ... );
}

第二种方法取决于API。假设您的回调收到一个void*,您可以将其传递给ThirdPartyFunction,实现如下:

struct MyClass {
    int MyCallbackMethod( ... );
};
static int MyStaticCallback(void* userData) {
    MyClass *instancePointer = (MyClass*)userData;
    instancePointer->MyCallbackMethod();
}
int main(int argc, char* argv[]) {
    MyClass instanceOfMyClass;
    ThirdPartyFunction( &MyStaticCallback, (void*)(&instanceOfMyClass));
}

在您的情况下,看起来cls指针是传递回回调的指针,apc_cls/dh_cls是您传递给第三方函数进行注册的指针。