4

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

我怎样才能得到扣除工作?

4

4 回答 4

6

您可以像这样调用该函数:

f<int&>(i, g);

但现在我也将通过引用传递。

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

template <typename T, typename F>
void f(T t, F func) 
{ 
    func(t); //e.g
}
于 2010-03-29T16:04:41.033 回答
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即可。

于 2010-03-29T20:19:20.637 回答
5

我认为您需要:

void f(T t, void (*func)(T&)) {}

或者:

void g(int s) {}

但是我更喜欢:

template<typename T, typename T2> 
void f(T t, T2 func) {}

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

于 2010-03-29T16:03:04.577 回答
1
template<typename T>
void f(T t, void (*func)(T)) {}

这里的关键是您T在两个参数中都使用了。这意味着类型必须完全匹配。

void g(int& s) {}

int i = 7;
f(i, g);

在您的代码中,您传递了一个int和一个采用int&to的函数f()。这些是不同的类型,但您的模板f需要两个相同的类型。正如其他人所建议的那样,最简单的解决方法是将函数也设为模板。

template <typename T, typename F>
void f(T t, F func) 
{ 
    func(t);
}
于 2010-03-29T16:11:39.830 回答