Writing a helper class for generating a particular category of C callback wrappers around C++ methods
Another exercise in C++ template programming. The post Writing a helper class for generating a particular category of C callback wrappers around C++ methods appeared first on The Old New Thing.

A common pattern for C callbacks is to accept a function pointer and a void*
, and then the callback function receives that pointer in addition to the parameters specific to the callback.
// Hypothetical callback typedef int (*callback_t)( void* context, int arg1, char const* arg2, double arg3); void RegisterCallback(callback_t callback, void* context);
If you’re writing code in C++, it’s more convenient to write the callback as a class member function.
struct Widget { int OnCallback( int arg1, char const* arg2, double arg3); static int OnCallbackStatic(void* context, int arg1, char const* arg2, double arg3) { auto self = (Widget*)context; return self->OnCallback(arg1, arg2, arg3); } void Register() { RegisterCallback(OnCallbackStatic, this); } };
Is there a way to simplify this boilerplate?
My idea was to use the conversion operator to deduce the callback function signature, and give the wrapper function the same signature. The wrapper function then forwards the parameters to the member function and propagates the result. Doing it this way means that the member function need not have the exact same signature, as long as the inputs and outputs are convertible.
templatestruct CallbackWrapperMaker { template static Ret callback(void* p, Args...args) { auto obj = (???*)p; return (obj->*F)((Args)args...); } template using StaticCallback = Ret(*)(void*, Args...); template operator StaticCallback () { return callback ; } }; template inline CallbackWrapperMaker CallbackWrapper = CallbackWrapperMaker (); struct Widget { int OnCallback( int arg1, char const* arg2, double arg3); void Register() { RegisterCallback( CallbackWrapper<&Widget::OnCallback>, this); } };
// usage:
The CallbackWrapper
is an empty object whose job is merely to be convertible to a C-style callback function. We use the conversion operator to detect the signature that we need to produce, and we use those template type parameters to generate the correct version of the callback
function.
The part we haven’t written yet is the code to cast the context parameter p
back to the original object type, like Widget
. To do that, we use a helper traits type that can extract the parent object from a pointer to member function.
templatestruct MemberFunctionTraits; template struct MemberFunctionTraits { using Object = T; }; template struct CallbackWrapperMaker { template static Ret callback(void* p, Args...args) { auto obj = (typename MemberFunctionTraits :: Object*)p; return (obj->*F)((Args)args...); } ⟦ ... rest as before ... ⟧ };
The nice thing about forwarding to the member function is that the member function need not accept the parameters in the same way as the callback. For example, we could have written
struct Widget { short OnCallback( long arg1, char const* arg2, double arg3); void Register() { RegisterCallback( CallbackWrapper<&Widget::OnCallback>, this); } };
and the compiler will automatically apply the normal integral promotions of arg1
from int
to long
and the return value from short
to int
.
The post Writing a helper class for generating a particular category of C callback wrappers around C++ methods appeared first on The Old New Thing.