1

I have a C API to a data source. To be notified that new data is available you give the API a callback in the form of a function pointer; your callback will be called when data comes in. The API’s header contains lines like this:

struct DataRecord { ... };
typedef void (*DataCallback)(DataRecord *data);

void set_data_callback(DataCallback processor);

My C++ class has an instance method with the signature

void MyClass::process_data(DataRecord *data);

and in the constructor of MyClass I’d like to set the new instance’s process_data method as the data callback for the C API. Following this answer I tried to write this code in the constructor:

typedef void (MyClass::data_callback_t)(DataRecord*);
data_callback_t callback = &MyClass::process_data;
set_data_callback(callback);

When I do this I get the error

error C2664: 'set_data_callback' : cannot convert parameter 2 from 'data_callback_t' to 'DataCallback'

There is no context in which this conversion is possible

(I am using Visual C++ 2010 Express, although I hope that doesn’t make a difference.)

How can I extract a C function pointer from an instance and a method?

Community
  • 1
  • 1
bdesham
  • 15,430
  • 13
  • 79
  • 123
  • 1
    Short answer is, you can't. Unless you're prepared to hardcode which instance is to be invoked, and then you can have a non-member such as `void process(DataRecord *data) { someInstance->process_data(data); }`. To get round that limitation, you'd need to modify the API to take a `void *stuff` when registering the callback. – Oliver Charlesworth Nov 20 '14 at 22:26
  • That's a really bad API, which does not allow passing a context-pointer... there are some non-standard libraries to create trampolines at runtime, and other flawed methods using static (or thread-local) variables. - - It's not quite as dire if the function does not return until it called the callback for the last time... – Deduplicator Nov 20 '14 at 22:37

1 Answers1

1

You can't. MyClass::process_data can be thought of as a void(MyClass*, DataRecord*), which is the wrong type. You'd have to wrap your class pointer into the call somehow.

One approach might be to introduce a type with a static pointer:

struct MyClassCallbackHelper
{
    static MyClass* myClass;

    static void callback(DataRecord* record) {
        myClass->process_data(record);
    }
};

So that you can do:

MyClassCallbackHelper::myClass = this;
set_data_callback(&MyClassCallbackHelper::callback);
Barry
  • 286,269
  • 29
  • 621
  • 977