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>
.
对于以下代码:
#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>
.