模板仿函数不能推导出引用类型

时间:2010-03-29 15:57:17

标签: c++ templates reference functor

我有一个仿函数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;
}

如何才能获得演绎?

4 个答案:

答案 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()重载的函数对象。但是你要面对的问题是必须知道它是否需要引用。要解决此问题,boostreference_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);
}