有一个功能
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
的声明必须保持不变。
答案 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}}模板参数与函数指针匹配。