我有C框架,提供经典的延迟回调执行API:
typedef void (*callback_t)(int value_1, int value_2, void* arg);
void schedule(callback_t callback, void* arg);
这里arg
是用户指定的任意值,将传递给回调,其他回调参数由框架传递。但实际上只有最后一个参数在处理程序中使用,并且必须从void*
显式转换。
考虑如何改变回调签名以匹配我对此解决方案的真实回复:
template <typename TArg, void (*Callback)(TArg*)>
void run(TArg* arg)
{
schedule([](int, int, void* arg)
{
Callback((TArg*)arg);
}, arg);
}
...
void handler(int* arg) // instead of handler(int, int, void* arg)
{
}
...
run<int, handler>(arg); // instead of schedule(handler, arg)
这里唯一的问题是必须在run
调用时显式指定回调参数类型。
有没有办法让编译器推断出这种类型? 理想情况下,执行代码应该只是:
run<handler>(arg);
初始问题还有另一种解决方案 - 创建自定义函数对象并将其作为用户参数传递给本机API。然后从void*
解压缩,执行真正的回调并删除函数对象。但是,当未执行回调时,操作取消存在问题。它需要更多的工作才能正确实现,如果有更简单的方法,我宁愿忽略它。
答案 0 :(得分:1)
预处理器每隔一段时间就可以派上用场了:
#define myRun(fun, arg) (::run<::std::remove_pointer_t<decltype(arg)>, fun>(arg))
请注意,这将不多次评估arg
或fun
。结果也是一个带括号的表达式(而不是像声明那样更icky),因此就像普通的函数调用一样。
答案 1 :(得分:0)
使用std :: bind的不同方法(虽然无法测试):
typedef void (*callback_t)(int value_1, int value_2, void *arg);
void schedule(callback_t callback, void *arg)
{
}
template <typename TArg>
void run(void (*Callback)(TArg *), TArg *arg)
{
// needs to be freed
std::function<void()> *bound = new std::function<void()>(std::bind(Callback, arg));
schedule([](int, int, void *arg)
{
std::function<void()> &f = *(std::function<void()> *)arg;
f();
}, bound);
}
void foo(int *a)
{
}
int main()
{
int *arg = nullptr;
run(foo, arg);
}