Search code examples
c++c++11callbackfunction-pointerspointer-to-member

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


I use a third-party library that requires to have pointers to static functions passed as callback arguments. For now I have to do something like this:

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

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

What I would like to do is to replace the static callback function I have to provide by a member method of an instance of a C++ class. Something like this:

class MyClass
{
public:
    int MyCallbackMethod( ... );
};

int main(int argc, char* argv[])
{
    MyClass instanceOfMyClass;

    ThirdPartyFunction( &(????), ... );
}

My problem is that it doesn't compile when I pass &instanceOfMyClass::MyCallbackMethodto ThirdPartyFunction(). When starting a thread (say, a std::thread) one passes (&MyClass::MyCallbackMethod, this) but in this case, the ThirdPartyFunction (that seems to be written in C rather than in C++ ?) doesn't allow me to pass a function pointer and an object owning the method.

On the other hand, if I declare static int MyCallbackMethod in MyClass, of course it works but I don't have an instance and it is not what I want.

My question is simple: is it possible to pass something like (&MyClass::MyCallbackMethod, this) (instance method) in place of &MyClass::MyCallbackMethod (static method)? I'm using C++11.

Thanks in advance for your help!

EDIT 1

I use libmicrohttpd (see microhttpd.h)

Function "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);

and MHD_AcessHandlerCallback, for example, is declared as:

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

So I have to use a function that has this signature. I would like to use the same signature but on an instance method rather than a static function.


Solution

  • You cannot pass a pointer to member function in place of a pointer to a non-member or a static member function, because member functions require an object on which they are invoked. A pointer to that object becomes the implicit this parameter of your member function.

    If you need to dispatch a call to a member function, there needs to be a way to find the object on which the function is being invoked. There are two general approaches here:

    • Put the object pointer to your object in some place known to your program. Pass a static function that finds the object target, and invokes callback on it
    • Rely on the API functionality that lets you pass "user data" to your callback, placing an object pointer there.

    In both cases you register a static or a non-member function as a callback function to your third-party API.

    Here is an example of the first approach:

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

    The second approach depends on the API. Assuming that your callback receives a void* that you can pass to ThirdPartyFunction, the implementation goes like this:

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

    In your situation it looks like the cls pointer is what's being passed back to your callback, and apc_cls / dh_cls is what you pass to third-party function for registration.