为什么对模板的调用没有歧义?
Why isn't this call to a template ambiguous?
我声明了两个模板,第一个将参数 x
从类型 T
转换为类型 U
,第二个将类型 U
转换为类型 T
.如果我用 10 调用 cast
,编译器不会报错。我认为两者都符合使用要求,因此应该有歧义,是这样吗?此代码打印 10.
#include <iostream>
template<typename T, typename U>
U cast(T x) {
return static_cast<U>(x);
}
template<typename T, typename U>
T cast(U x) {
return static_cast<T>(x);
}
int main() {
std::cout << cast<int,float>(10) << '\n';
}
实例化没有歧义,因为函数参数与第一个模板参数完全匹配:文字 10
是一个 int
,这也是为第一个模板类型明确指定的。
当参数类型与明确指定的类型不匹配时,您可以使实例化不明确(因此,需要进行转换),例如
// error: call of overloaded 'cast<int, float>(unsigned int)' is ambiguous
std::cout << cast<int,float>(10u) << "\n";
当您使用 cast<int, float>
时,两个模板都会被考虑。
template<typename T=int,typename U=float>
U cast(T x);
template<typename T=int,typename U=float>
T cast(U x);
然后我们替换:
template<typename T=int,typename U=float>
float cast(int x);
template<typename T=int,typename U=float>
int cast(float x);
此时,没有类型可以推导。所以我们去解决重载问题。
在一种情况下,我们可以采用 int
并在 调用 转换时转换为 float
,而在另一种情况下,我们采用 int
并在 调用 转换时转换为 int
。请注意,我根本没有关注演员表的 body;正文与重载决议无关。
第二个非转换(在调用点)是更好的匹配,因此选择了重载。
如果你这样做了:
std::cout << cast<int>(10) << "\n";
事情变得更有趣了:
template<typename T=int,typename U=?>
U cast(T x);
template<typename T=int,typename U=?>
T cast(U x);
对于第一个,我们无法推导出U
。对于第二个,我们可以。
template<typename T=int,typename U=?>
U cast(int x);
template<typename T=int,typename U=int>
int cast(int x);
所以这里我们有一个可行的重载,它被使用了。
我声明了两个模板,第一个将参数 x
从类型 T
转换为类型 U
,第二个将类型 U
转换为类型 T
.如果我用 10 调用 cast
,编译器不会报错。我认为两者都符合使用要求,因此应该有歧义,是这样吗?此代码打印 10.
#include <iostream>
template<typename T, typename U>
U cast(T x) {
return static_cast<U>(x);
}
template<typename T, typename U>
T cast(U x) {
return static_cast<T>(x);
}
int main() {
std::cout << cast<int,float>(10) << '\n';
}
实例化没有歧义,因为函数参数与第一个模板参数完全匹配:文字 10
是一个 int
,这也是为第一个模板类型明确指定的。
当参数类型与明确指定的类型不匹配时,您可以使实例化不明确(因此,需要进行转换),例如
// error: call of overloaded 'cast<int, float>(unsigned int)' is ambiguous
std::cout << cast<int,float>(10u) << "\n";
当您使用 cast<int, float>
时,两个模板都会被考虑。
template<typename T=int,typename U=float>
U cast(T x);
template<typename T=int,typename U=float>
T cast(U x);
然后我们替换:
template<typename T=int,typename U=float>
float cast(int x);
template<typename T=int,typename U=float>
int cast(float x);
此时,没有类型可以推导。所以我们去解决重载问题。
在一种情况下,我们可以采用 int
并在 调用 转换时转换为 float
,而在另一种情况下,我们采用 int
并在 调用 转换时转换为 int
。请注意,我根本没有关注演员表的 body;正文与重载决议无关。
第二个非转换(在调用点)是更好的匹配,因此选择了重载。
如果你这样做了:
std::cout << cast<int>(10) << "\n";
事情变得更有趣了:
template<typename T=int,typename U=?>
U cast(T x);
template<typename T=int,typename U=?>
T cast(U x);
对于第一个,我们无法推导出U
。对于第二个,我们可以。
template<typename T=int,typename U=?>
U cast(int x);
template<typename T=int,typename U=int>
int cast(int x);
所以这里我们有一个可行的重载,它被使用了。