在函数参数化的模板中推导参数类型

时间:2015-01-27 14:36:04

标签: c++ templates type-deduction

我有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*解压缩,执行真正的回调并删除函数对象。但是,当未执行回调时,操作取消存在问题。它需要更多的工作才能正确实现,如果有更简单的方法,我宁愿忽略它。

2 个答案:

答案 0 :(得分:1)

预处理器每隔一段时间就可以派上用场了:

#define myRun(fun, arg) (::run<::std::remove_pointer_t<decltype(arg)>, fun>(arg))

请注意,这将多次评估argfun。结果也是一个带括号的表达式(而不是像声明那样更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);
}