用指向实例中方法的指针替换参数中的静态函数指针

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

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

static int MyCallback( ...)
{
    // Callback code here...
}

int main( int argc, char* argv[])
{
    ThirdPartyFunction( &MyCallback, ... );
}

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

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::MyCallbackMethod静态方法)?我正在使用 C++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 功能,您可以将 "user data" 传递给回调,并在其中放置一个对象指针。

在这两种情况下,您都将静态或非成员函数注册为第三方的回调函数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_clsyou 传递给第三方函数进行注册。