如何调用模板函数更简洁

时间:2015-03-09 08:20:17

标签: c++ templates

有一个功能

template <class ...T>
void foo(std::function<void(T...)> callback);

我通过回调。

我想做一些像

这样的事情
foo(bar);

例如,bar

void bar(int a, long b, double c, float d);

但是这给了我

error: no matching function for call to bar(void (&)(int, long int, double, float))

我必须将foo称为

foo(std::function<void(int, long, double, float)>(bar));

太冗长了。甚至

foo<int, long, double, float>(bar);

本来会更好。

foo(bar);

会很理想。

无论如何,如何调用foo更简洁?

修改: foo的声明必须保持不变。

3 个答案:

答案 0 :(得分:8)

我编写了一个包装函数,将函数指针转换为std::function包装器:

template <typename... T>
void foo(std::function<void (T...)> f) {}

template <typename... T>
void foo(void (*f)(T...)) {
    foo(std::function<void (T...)>(f));
}
然后可以以任一方式调用

foo()

void bar(int,double) {}

void foo_caller() {
    foo(std::function<void (int,double)>(bar));
    foo(bar);
}

附录:非静态成员函数包装器

相同的方法可用于指向成员的函数 - 只需添加另一个重载:

template <typename C,typename... T>
void foo(void (C::*f)(T...)) {
    foo(std::function<void (C *,T...)>(f));
}

注意成员函数的this指针的额外第一个参数。用法类似:

struct quux {
    void mf(char *,double) {}
};

void foo_caller() {
    foo(&quux::mf);
}

答案 1 :(得分:1)

如果您的foo定义没有一成不变,可以将其更改为

#include <functional>

template <class Ret, class ...T>
void foo(Ret callback(T... params))
{
}

void bar(int a, long b, double c, float d){}

int main() 
{
    foo(bar);
}

答案 2 :(得分:1)

如果您知道将普通的函数指针传递给foo,而不仅仅是任何C ++ 11 lambda,则可以将foo重新定义为:

template <class ...T>
void foo(void(*callback)(T...)) {
   // .....
}

如果你想支持lambdas,你可以使用类型

更通用
template <class LambdaType>
void foo(LambdaType callback) {
   // .....
}

这种方法的缺点是,如果你传递的不是函数或lambda,你会得到来自foo内部的奇怪的模板错误消息。


使用原始解决方案,编译器在将T...int, long, double, float匹配时遇到问题,可能是因为它是嵌套类型。

如果我告诉您将void(int, double)MyTempalte<T...>匹配,您就不会知道我打算将T...替换为int, double,因为您不会MyTemplate知道MyTemplate对其参数的作用。也许std::function首先对其模板参数做了一些奇怪的事情?

同样,编译器不知道如何将{{1}}模板参数与函数指针匹配。