【发布时间】:2018-07-21 00:34:15
【问题描述】:
当 C++ 应用程序使用在 API 中具有回调的 C 库时,一个常见的模式是应用程序定义静态函数,将一些 void* 用户数据参数转换为类指针,然后调用适当的成员函数。复制浪费了写作和阅读的时间。有一个模板函数来为我做这个包装会很好。
我已经找到了一部分……
// 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 (*)()')
// A bit more explicit but without providing 'Args' to staticCallback
registerAndCallCallback(0,
reinterpret_cast<GenericCallback>(
&staticCallback<decltype(&MyClass::callbakcOne),
&MyClass::callbakcOne>),
this);
// main.cpp:52:36: error: too few arguments to function call, expected 1, have 0
// (instance->*cb)(args...);
// ~~~~~~~~~~~~~ ^
// main.cpp:37:22: note: in instantiation of function template specialization 'MyClass::staticCallback<void (MyClass::*)(double), &MyClass::callbakcOne>' requested here
// &staticCallback<decltype(&MyClass::callbakcOne),
// ^
// 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;
}
我如何编写模板函数staticCallback,以便我可以给它一个成员函数来包装它可以为我处理参数类型等?
【问题讨论】:
-
也许你可以将回调放在一个单独的命名空间中,除了一个类,这样你就可以摆脱所有
MyClass::的东西,以及类成员函数指针的许多其他复杂性跨度>