Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing a qualified non-static member function as a function pointer

Tags:

c++

I have a function in an external library that I cannot change with the following signature:

void registerResizeCallback(void (*)(int, int))

I want to pass in a member function as the callback, as my callback needs to modify instance variables.

Obviously this isn't possible with a simple:

registerResizeCallback(&Window::Resize);

so I'm not really sure how to solve the problem.

like image 378
ICR Avatar asked Dec 05 '22 07:12

ICR


1 Answers

As Igor Oks indicates, you can't do this. The remainder of this question is not so much an answer to your problem, but a discussion of how something like this should work with a properly designed callback API (it appears the one you're using isn't).

Most well-designed callback interfaces let you provide a "void *" or some other way to get a context in the callback. A common way to use this with C++ is to pass an object pointer in the void * context parameter, then the callback function can cast it back into an object pointer and call the member method to do the real work. It's too bad the callback API you're using doesn't provide for context data.

Strictly speaking, the callback must be extern "C", but using static member methods for callbacks is common and I think in practice there's never a problem. (This is assuming that the callback API is a C interface, which is by far the most common).

An example:

// callback API declaration's

extern "C" {
    typedef unsigned int callback_handle_t;

    typedef void (*callback_fcn_t)( void* context, int data1, int data2);

    callback_handle_t RegisterCallback( callback_fcn_t, void* context);
    void UnregisterCallback( callback_handle_t);
}

// ----------------------------------

// prototype for wrapper function that will receive the callback and 
//  transform it into a method call

extern "C" 
static void doWorkWrapper( void* context, int data1, int data2);


// the class that does the real work

class worker {
public:
    worker() {
        hCallback = RegisterCallback( doWorkWrapper, this);
    }

    ~worker() {
        UnregisterCallback( hCallback);
    }

    void doWork( int data1, int data2) {
        // ... 
    };

private:
    callback_handle_t hCallback;
};

// the wrapper that transforms the callback into a method call
extern "C" 
static void doWorkWrapper( void* context, int data1, int data2)
{
    worker* pWorker = static_cast<worker*>( context);

    pWorker->doWork( data1, data2);
}
like image 194
Michael Burr Avatar answered Dec 29 '22 00:12

Michael Burr