C++ Member Functions to Functions
So, you’re interfacing your C++ classes with some C library, and you’d like to wire a C callback to some C++ method. You’ve got a method:
void SubClass::setFoo(int) throw(SomeException);
but the callback prototype the C library gives you is just:
int (*DumbSetter)(int, void *);
So, okay, you write a wrapper function to use as the callback:
int wrap_setFoo(int value, void *data) {
BaseClass *base_instance = static_cast<BaseClass *>(data);
SubClass *instance = static_cast<SubClass *>(base_instance);
try {
instance->setFoo(value);
return 1;
} catch (SomeException) {
return 0;
} catch (...) {
std::cerr << "Unexpected exception in callback; exiting\n";
abort();
}
}
There are two important things to note here:
- if the data pointer wasn’t cast directly from
SubClass *tovoid *, but was instead cast to a superclass (BaseClass) first, you’ll need to reverse the process when casting away fromvoid *, as shown here. - you can’t let C++ exceptions escape into C functions; they have the potential to wreak havoc on the C stack. If we get an exception we’re not already prepared to handle, we have to do something rather than let it escape. Aborting is one option; using the C API’s error reporting facilities are another.
So, okay. That wasn’t too bad. But now let’s say you’ve got many different
setFoo, setBar, setBaz, setHoge, ... setXYZZY member functions,
in many different classes. That’s a lot of copy and pasting…
Provided they all share the same signature, however, you can use C++ templates to automate the generation of the wrapper functions. Here’s how:
template <typename Base, typename T, void (T::*setter)(int)>
int wrap_setter(int value, void *data) {
Base *base_instance = static_cast<Base *>(data);
T *instance = static_cast<T *>(base_instance);
try {
(instance->*setter)(value);
return 1;
} catch (SomeException) {
return 0;
} catch (...) {
std::cerr << "Unexpected exception in callback; exiting\n";
abort();
}
}
As noted earlier, if you know for sure that the object pointer was originally
cast or coerced directly to void * from T *, then you can leave off the
intermediate cast to Base *, and the Base argument. If not, however,
Base * must be the original type that was converted to void *.
So, anyway, there’s the template. At this point, you can register a callback
for SubClass::setFoo as
&wrap_setter<BaseClass, SubClass, &SubClass::setFoo>, rather than
needing a separate &wrap_setFoo. setBar, setBaz etc. all work
similarly, without writing any additional wrapper functions by hand.
Update: Murray Cumming points out that a double cast isn’t strictly necessary unless multiple inheritance is involved. I elected to include it here because omitting the intermediate cast when it is needed is a problem the compiler can’t catch. Better safe than sorry.
More importantly, however, he also reminded me that casting from the base
class to the subclass using static_cast<> will not work when there is
virtual inheritance involved (the compiler will alert you of such cases).
To deal with them, you would need to use another version of the function
template which used dynamic_cast<> for the second cast.