When a C++ application uses a C library that has callbacks in the API, a common pattern is for the app to define static functions that translate some void*
user data argument into a class pointer and then call the appropriate member function. The duplication wastes time both writing and reading. It would be nice to have a template function to do this wrapping for me.
I've got part of the way there already...
// C library with some callbacks
typedef void (*CallbackTypeOne)(void* userdata, double arg1);
typedef void (*CallbackTypeTwo)(void* userdata, int arg1);
typedef void (*CallbackTypeThree)(void* userdata, int arg1, float arg2);
typedef void(*GenericCallback)();
void registerAndCallCallback(int typeID, GenericCallback callback, void* userdata)
{
switch (typeID) {
case 0: ((CallbackTypeOne)callback)(userdata, 42.0); break;
case 1: ((CallbackTypeTwo)callback)(userdata, 42); break;
case 2: ((CallbackTypeThree)callback)(userdata, 42, 42.0f); break;
};
}
// C++ app using the above library
class MyClass
{
public:
MyClass()
{
// Ideal short syntax, but doesn't compile
registerAndCallCallback(0,
reinterpret_cast<GenericCallback>(
&staticCallback<MyClass::callbakcOne>),
this);
// main.cpp:26:36: error: reinterpret_cast cannot resolve overloaded function 'staticCallback' to type 'GenericCallback' (aka 'void (*)()')
registerAndCallCallback(1, reinterpret_cast<GenericCallback>(&staticCallback<MyClass::callbakcTwo>), this);
registerAndCallCallback(2, reinterpret_cast<GenericCallback>(&staticCallback<MyClass::callbakcThree>), this);
// This works, but I feel there should be a nicer way that avoids having to pass the callback arguments. Avoiding the duplication in decltype would be nice too.
registerAndCallCallback(0,
reinterpret_cast<GenericCallback>(
&staticCallback<decltype(&MyClass::callbakcOne),
&MyClass::callbakcOne, double>),
this);
registerAndCallCallback(1, reinterpret_cast<GenericCallback>(&staticCallback<decltype(&MyClass::callbakcTwo), &MyClass::callbakcTwo, int>), this);
registerAndCallCallback(2, reinterpret_cast<GenericCallback>(&staticCallback<decltype(&MyClass::callbakcThree), &MyClass::callbakcThree, int, float>), this);
}
void callbakcOne(double arg1) {}
void callbakcTwo(int arg1) {}
void callbakcThree(int arg1, float arg2) {}
template<typename MemberCB, MemberCB cb, typename... Args>
static void staticCallback(void* userdata, Args... args)
{
auto instance = reinterpret_cast<MyClass*>(userdata);
(instance->*cb)(args...);
}
};
int main()
{
MyClass myclass;
return 0;
}
Is there some way I can change the staticCallback
template to automatically resolve the arguments of MyClass::callback*
?
Aucun commentaire:
Enregistrer un commentaire