我在思考C语言中void*
的一个用例,我试图以最惯用的方式将该代码转换为C ++而不会降低效率。这是问题,以下是解决方案
void callback(void* args) {
Something* something = static_cast<Something*>(args);
// use something
}
Something something;
add_callback(callback, &something);
只要某个事件发生了某个事件,就会调用回调。在C ++中执行此操作的惯用方法(帮助我找到一个更好的解决方案,如果你认为这是不对的)就像是 以下
Something something;
add_callback([=something]() {
// do something
});
然后add_callback()
将在内部擦除lambda的类型并将其存储在std::function<>
中以便在时机到来时进行回调。与旧版本相比,这样做的好处是回调更好地封装了它的状态。
但是我看到的问题是,每次调用回调时,这都会导致虚函数调度的不必要开销。 (假设即使没有可证明的开销,只是因为我很好奇,它只是开销),我能想到的唯一解决方案是在这里使用std::any
(但这需要对象可以复制构造)并且使用std::any
作为成员变量来制作回调的签名,或者只是将std::any
传递给函数(存储为函数指针)并放弃回调状态的封装。但是有些东西告诉我有更好的解决方案......
答案 0 :(得分:0)
您可以使用函数模板简化C ++中完整类型的使用,但不能避免使用static_cast
。
示例:
struct CallbackHandler
{
void doSomething() {}
}
template <typename T>
void cpp_callback(T* args)
{
// Use args with full access to T.
args->doSomething();
}
template <typename T>
void callback(void* args)
{
cpp_callback(static_cast<T*>(args));
}
int main()
{
add_callback(callback<CallbackHandler>, new CallbackHandler);
}
答案 1 :(得分:0)
我认为你不能同时获得类型擦除,类型安全,零开销。
我想出的最好的是这样的:
typedef void (*func_t)(void *p);
template<typename T, void (T::*F)()>
struct CB_helper
{
static void func(void *p)
{
T *t = static_cast<T*>(p);
(t->*F)();
}
};
template<typename T, void (T::*F)()>
func_t CB()
{
return CB_helper<T, F>::func;
}
然后你可以用它:
struct Something
{
void do();
};
Something some;
add_callback(CB<Something, &Something::do>(), &some);
缺点是您需要为要使用的每种类型的回调设置新的CB
。你可以做一些智能元编程,每个参数只有一个版本。