就像常规(意即non-template)functions一样,function templates 也可以被重载
// 传回两个 ints 中的较大者
inline int const& max (int const& a, int const& b) {
return a < b ? b : a;
}
// 传回两任意类型的数值中的较大者
template <typename T>
inline T const& max (T const& a, T const& b) {
return a < b ? b : a;
}
// 传回三个任意类型值中的最大者
template <typename T>
inline T const& max (T const& a, T const& b, T const& c) {
return ::max (::max(a,b), c);
}
int main()
{
// 调用「接受三个自变量」的函数
::max(7, 42, 68);
// 调用 max<double>(经由自变量推导)
::max(7.0, 42.0);
// 调用 max<char>(经由自变量推导)
::max('a', 'b');
// 调用「接受两个 int 自变量」的 non-template 函数
::max(7, 42);
// 调用 max<int>(经由自变量推导)
::max<>(7, 42);
// 调用 max<double>(无需自变量推导)
::max<double>(7, 42);
// 调用「接受两个 int 自变量」的 non-template 函数
::max('a', 42.7);
}
/* ICL7.1/g++ 3.2 顺利通过本例。VC6 无法把最后一个调用匹配到常规的(non-template)函数 max(), 造成编译失败 。 VC7.1 可顺利编译 , 但对倒数第二个调用给出警告 : 虽然它调用的是 function template max(),但它发现常规函数 max()与这个调用更匹配。*/
这个例子说明:
1、non-template function 可以和同名的 function template 共存,也可以和其相同类型 的具现体共存。
2、当其它要素都相等时,重载解析机制会优先选择 non-template function,而不选 择由 function template 实例化后的函数实体。
::max(7, 42); // 两个自变量都是 int,吻合对应的 non-template function
3、如果可由 template 产生更佳匹配,则 template 具现体会被编译器选中
::max(7.0, 42.0); // 调用 max<double>(经由自变量推导)
::max('a', 'b'); // 调用 max<char>(经由自变量推导)
4、调用端也可以使用空的 template argument list,这种形式告诉编译器「只从 template 具现体中挑选适当的调用对象」,所有template parameters 都自call parameters 推导而得:
::max<>(7, 42); // 调用 max<int>(经由自变量推导)
5、自动类型转换只适用于常规函数,在templates 中不予考虑,因此前述最后一个调用调用的是 non-template 函数。在该处,'a' 和 42.7 都被转型为 int:
::max('a', 42.7); // 本例中只有 non-template 函数才可以接受两个不同类型的自变量
6、总是把所有形式的重载函数写在它们被调用之前
7、重载 function templates 时,不同的重载形式之间最好只存在「绝对必要的差异」。
各重载形式之间应该只存在「参数个数的不同」或「参数类型 的明确不同」,否则可能引发各种副作用。 举个例子, 如果你以一个 「by value 形式的 max()」 重载一个「by reference 形式的 max()」 (注:两者之间的差异不够明显),就无法使用「三自变量」版本的 max()