Reputation: 141
I'm trying to integrate a C library with callbacks into a templated C++ class. For simplicity say the C library operates as
utility_class data;
callback(double input[], void* data);
void* mem;
c_library_init(mem);
c_library_data(mem, &data);
c_library_callback(mem, &callback);
c_library_action(mem);
c_library_free(mem);
If I had a non-templated C++ class then this would be straightforward,
extern "C"
void callback(double input[], void* data) {
static_cast<example>(data)->callback_impl(input);
}
class example {
private:
void* mem_;
public:
example(): mem_(NULL) {
c_library_init(mem);
c_library_data(mem, (void*)this);
c_library_callback(mem, &callback);
}
~example {
c_library_free(mem);
}
void action() {
c_library_action(mem);
}
void callback_impl(double input[]) {
...
}
};
But if example
is templated then callback
doesn't know to what to cast the void pointer. Making callback
a static class method,
template <class T>
class example {
private:
void* mem_;
public:
example(): mem_(NULL) {
c_library_init(mem);
c_library_data(mem, (void*)this);
c_library_callback(mem, &example<T>::callback);
}
~example {
c_library_free(mem);
}
void action() {
c_library_action(mem);
}
void callback_impl(double input[]) {
...
}
static void callback(double input[], void* data) {
static_cast<example<T> >(data)->callback_impl(input);
}
};
compiles, but the executable inevitable dies with a malloc error which I can only assume is because of a new/free conflict due to the lack of a proper extern. Defining the static method out-of-line with an explicit extern "C"
yields the same behavior.
Is there any hope? Thanks!
Updated: Added the C library call to set the user data used in the callback.
Upvotes: 1
Views: 390
Reputation: 1756
How about solving this with polymorphism? With a base class like this
struct example_base {
virtual void callback(double[]) = 0;
};
Your templated class could inherit from it like this
template <typename T>
struct example : public example_base {
example() : mem_(nullptr) {
c_library_init(mem_);
c_library_data(mem_, this);
c_library_callback(mem_, callback_dispatch);
}
void callback(double[]) override;
void* mem_;
};
And the callback
member function could be called with
extern "C" void callback_dispatch(double input[], void* data) {
static_cast<example_base>(data)->callback(input);
}
Upvotes: 2