如何使对模板函数的调用不那么冗长

How to make a call to a template function less verbose

本文关键字:调用 何使 函数      更新时间:2023-10-16

有一个函数

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声明必须保持不变。

我会编写一个将函数指针转换为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);
}

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

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

如果你想支持 lambda,你可以更通用地使用

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

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


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

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

同样,编译器不知道如何将std::function模板参数与函数指针匹配。

如果您的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);
}