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

mac*_*ekp 4 c++ templates reference functor

我有一个仿函数f,它接受函数func和与func相同类型的参数t.由于编译错误(调用没有匹配函数),我无法将g传递给f f(int&, void (&)(int&)).如果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;
}
Run Code Online (Sandbox Code Playgroud)

我怎样才能获得演绎?

Unc*_*ens 6

您可以像这样调用函数:

f<int&>(i, g);
Run Code Online (Sandbox Code Playgroud)

但现在我也将通过参考传递.

一般来说,我也将该函数设为模板类型:

template <typename T, typename F>
void f(T t, F func) 
{ 
    func(t); //e.g
}
Run Code Online (Sandbox Code Playgroud)


Cha*_*tie 5

我想你需要:

void f(T t, void (*func)(T&)) {}
Run Code Online (Sandbox Code Playgroud)

要么:

void g(int s) {}
Run Code Online (Sandbox Code Playgroud)

但是我更喜欢:

template<typename T, typename T2> 
void f(T t, T2 func) {}
Run Code Online (Sandbox Code Playgroud)

因为这将适用于函数和函子.


Joh*_*itb 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)) {}
Run Code Online (Sandbox Code Playgroud)

通过使用identity<T>::type,您可以禁用左侧的扣除.一旦T确定在右侧,将T被引入左侧并产生最终参数类型.

一个人建议将右侧作为模板参数 - 这是一件好事,因为它可以接受带有operator()重载的函数对象.但是你要面对的问题是必须知道它是否需要引用.为了解决这个问题,boostreference_wrapper(顺便说一下,boost也有identity上面的模板).

template<typename T, typename F>
void f(T t, F func) {}
Run Code Online (Sandbox Code Playgroud)

现在,如果你想传递引用而不是副本,你可以这样做

int i;
f(boost::ref(i), some_function);
Run Code Online (Sandbox Code Playgroud)

ref返回一个可隐式转换为的reference_wrapper对象T&.因此,如果您调用func(t),t则会自动转换为目标引用.如果您不想传递引用,只需i直接传递即可.