我有一个仿函数f,它接受函数func和与func相同类型的参数t。由于编译错误(调用f(int&, void (&)(int&))
没有匹配函数),我无法将g传递给f。如果g将采用非引用参数g(int s),则编译完成。或者,如果我手动指定模板参数f<int&>(i, g)
,编译也会完成。
template<typename T>
void f(T t, void (*func)(T)) {}
void g(int& s) {}
int main(int, char*[])
{
int i = 7;
f(i, g); // compilation error here
return 0;
}
如何才能获得演绎?
答案 0 :(得分:6)
您可以像这样调用函数:
f<int&>(i, g);
但现在我也将通过参考传递。
一般来说,我也将该功能设为模板类型:
template <typename T, typename F>
void f(T t, F func)
{
func(t); //e.g
}
答案 1 :(得分:5)
我认为你需要:
void f(T t, void (*func)(T&)) {}
或:
void g(int s) {}
但我更喜欢:
template<typename T, typename T2>
void f(T t, T2 func) {}
因为这将适用于函数和函子。
答案 2 :(得分:5)
问题在于,如果在模板中,其中一个函数参数在推导开始之前不是引用类型,那么该参数将永远不会推导为引用类型。因此,在左侧的演绎中,T
会产生int
,但在右侧的演绎中,T
会产生int&
。这是一个错误的匹配,编译器抱怨。
最好是使函数参数与函数指针的参数类型相同:
template<typename T> struct identity { typedef T type; };
template<typename T>
void f(typename identity<T>::type t, void (*func)(T)) {}
使用identity<T>::type
,您可以在左侧禁用扣除。在右侧确定T
后,T
将被置于左侧并产生最终参数类型。
有人建议将右侧作为模板参数 - 这是一件好事,因为它可以接受operator()
重载的函数对象。但是你要面对的问题是必须知道它是否需要引用。要解决此问题,boost
已reference_wrapper
(顺便说一下,boost
上面还有identity
模板。
template<typename T, typename F>
void f(T t, F func) {}
现在,如果你想传递引用而不是副本,你可以这样做
int i;
f(boost::ref(i), some_function);
ref
返回一个reference_wrapper对象,该对象可以隐式转换为T&
。因此,如果您致电func(t)
,t
会自动转换为目标参考。如果您不想传递引用,只需直接传递i
即可。
答案 3 :(得分:1)
template<typename T>
void f(T t, void (*func)(T)) {}
这里的关键是你在两个参数中都使用了T
。这意味着类型必须完全匹配。
void g(int& s) {}
int i = 7;
f(i, g);
在您的代码中,您传递了int
和一个将int&
传递给f()
的函数。这些是不同的类型,但f
的模板需要两个相同类型。正如其他人所建议的那样,最简单的修复方法是将该功能作为模板。
template <typename T, typename F>
void f(T t, F func)
{
func(t);
}