通过使用模板:
template <class T>
T GetMax (T a, T b) {
return (a>b?a:b);
}
然后
int main () {
int i=5, j=6, k;
long l=10, m=5, n;
k=GetMax(i,j); // line 1
n=GetMax<int>(l,m); // line 2
n=GetMax<double>(l,m); // line 3
cout << k << endl;
cout << n << endl;
return 0;
}
我的问题是:
为什么我需要这样做:
n=GetMax<int>(l,m); // line2
如果我能做到
n=GetMax(l,m); // line 2
为什么要编译?
n=GetMax<double>(l,m);
当l和m是与双精度相差甚远的整数时?
在这种情况下,您可以认为模板实例化是一个简单的文本替换(离它不远),也就是说,一旦您弄清楚了模板参数。所以:
- 让编译器从操作数中找出类型。由于它们匹配,因此
T
被证明是int
.您可以在标准中找到对匹配模板参数进行排名的确切逻辑。你的案子很简单。
找出模板参数后,进行替换,因此您的函数如下所示:
int GetMax (int a, int b) {
return (a>b?a:b);
}
当您使用多个参数并且与继承等有许多可能的匹配项时,它确实会被编译。
对于您的情况,您可以通过对参数使用两种不同类型的参数来引发相等的匹配,即:GetMax(i,l)
.T
有两个候选者:double
int
,两者都同样好。
这与著名的SFINAE(替换失败不是错误)有关。编译器尝试为可能的参数组合生成版本,如果失败,则不考虑最终排名。在您的案例中,两个替换成功。
你明确声明 T 是
int
.因此,编译器不会调用自动参数匹配。实例化版本看起来与 1 相同。您明确指出 T 在
double
.同样,编译器不会调用有关类型的任何逻辑。
它盲目地生成double
版本,并使用它:
double GetMax (double a, double b) {
return (a>b?a:b);
}
使用double
将int
传递给函数是合法的,会发生隐式转换。
这是完全合法的:
void f(double d) {};
int main(){
int i = 5;
f(i);
}
底线:
确定模板类型与调用函数是不同的逻辑。将其视为单独的阶段。类型推导旨在对调用有意义,但这是一个单独的部分。
您可以省略模板函数上的类型,因为它们是在编译时扣除
的第二个问题,没有错误,因为整数可以优雅地回退到双精度,因此它们将被转换并在模板逻辑上用作双精度。