C++ 模板推导不起作用

C++ template deduction is not working

对于以下代码:

#include<functional>
template<typename T>
void f(std::function<void(T)> g) {
}

template<typename T>
void g(T x) {
}

int main() {
   f(&g<int>);
}

C++14 编译器产生错误:

 no matching function for call to 'f(<unresolved overloaded function type>)'
     f(&g<int>);

我很好奇为什么模板参数推导在这里不起作用。 似乎,给定 g 的参数是 int 类型,我们可以推断出 f 的参数是 std::function<void(int)> 类型,因此 f 中的 T = int。为什么这不会发生?我对解释这一点的 C++ 标准的相关部分感兴趣。 T 是否出现在此处的非推导上下文中?

编译以下类似代码:

#include<vector>
template<typename T>
void f(std::vector<T> vec) { 
}


int main() {
    f(std::vector<int>{});
}

所以创建非推导上下文的不是尖括号。

您的函数需要一个类型为 std::function 的参数,但您向它传递了一个指向函数的指针。 &g<int>可以转换std::function参数类型,但是模板参数推导需要精确匹配([temp.deduct.call]/2,3,4允许的调整除外),用户定义不考虑转换。

f(std::function<void(int)>(g<int>)) 会起作用,因为您现在传递的是 std::function,因此模板参数推导会成功。

f<int>(&g<int>) 也有效,因为您现在明确指定了 T,它不再参与模板参数推导,并且将尝试用户定义的转换。

&g<int>的类型是void(*)(int)。因此,编译器会尝试生成一个带有签名 void f<>(void(*)(int)) 的函数,而您的模板无法做到这一点。类型 std::function<void(int)> 是完全不同的类型。

在您的类似代码中,对象 std::vector<int>{} 的类型为 std::vector<int>,因此编译器会尝试生成一个函数 void f<>(std::vector<int>),它可以通过推导 T成为int.

指定f<int>时,编译器不需要推导类型,因此不能不推导。此外,虽然在推导上下文中不考虑隐式转换,但它们在非推导上下文中被考虑。因此,通过显式提供类型并因此使函数参数成为非推导上下文,您允许编译器使用隐式转换将 std::function<void(int)> 参数初始化为 g<int>.