C++函数模板的重载
和普通函数一样,函数模板也可以重载。重载的函数模板,模板名称相同,但函数形参列表不同。
例如:
如果存在多个候选的模板,那么在实参推演过程中,编译器倾向于选择那些函数实参跟形参类型相近的模板。例如在上面的例子中,实参 1024 是一个整型,而候选函数模板中,其中一个的形参也是整型,那么该模板就会被选来进行实例化。
尽管定义重载函数模板同定义重载函数一样简单,但二者也有不同。重载函数没有二义性的问题,而重载函数模板则可能导致二义性。
仍以上面的重载模板 min 为例,使其既可以支持类型参数相同的情况,也可以支持类型参数不同的情况:
但是,在这种情况下其实可以不必重载函数模板。因为所有能够匹配 min(T, T) 的调用,也完全可以匹配 min(T, U)。所以应该只提供 min(T, U) 的声明,而 min(T, T) 应该被删除。
在某些情况下,尽管可以采用重载函数模板,但在进行程序设计时,仍然应当尽量少地使用,以避免不小心带来的二义性。
在 main() 函数中,我们对这些不同版本的 display() 函数进行了调用,以展示函数模板重载的工作方式。
例如:
template <typename Type> Type min(const Type*, int); // 注意第二个参数 template <typename Type> Type min(Type, Type); //两个参数类型相同在上述定义中,两个模板的模板形参相同,都是一个类型(typename Type),模板名称也相同,都是 min。但函数形参列表不一样,一个是 (const Type *, int),另一个是(Type, Type),所以这两个函数模板是重载的。
下面的主函数的定义说明了前面定义的两个模板如何使用:同函数重载一样,函数模板的返回类型不作为重载的判断条件。
#include <cmath> int main() { int ia[1024]; int ival = min(ia, 1024); // Type == int; min(const int*, int) double dval = min(1.1, 2.2); // Type == double; min(double, double) return 0; }在上述主函数的定义中,第 6 行的第二个参数是一个整型数 1024,从定义上来讲,此处更适合第一个函数模板,所以该处的调用得到的模板实例就是第一个模板的实例。
如果存在多个候选的模板,那么在实参推演过程中,编译器倾向于选择那些函数实参跟形参类型相近的模板。例如在上面的例子中,实参 1024 是一个整型,而候选函数模板中,其中一个的形参也是整型,那么该模板就会被选来进行实例化。
尽管定义重载函数模板同定义重载函数一样简单,但二者也有不同。重载函数没有二义性的问题,而重载函数模板则可能导致二义性。
仍以上面的重载模板 min 为例,使其既可以支持类型参数相同的情况,也可以支持类型参数不同的情况:
template <typename T> int min(T, T) { /* ...... */ } //两个参数类型相同的函数模板 template <typename T, typename U> int min(T, U); //两个参数类型不相同的函数模板如果以如下的形式使用函数模板,将会导致二义性:
min(1024, 512);因为在这个例子中,编译器无法决定到底该实例化哪个模板。第二个函数模板,虽然其模板参数声明为两个类型(T 和 U),但并没有限制这两个类型必须不同,所以语句“min(1024, 512);”也可以看做是调用第二个模板的实例。显然这样做会引起与第一个模板的冲突,从而导致编译错误。
但是,在这种情况下其实可以不必重载函数模板。因为所有能够匹配 min(T, T) 的调用,也完全可以匹配 min(T, U)。所以应该只提供 min(T, U) 的声明,而 min(T, T) 应该被删除。
在某些情况下,尽管可以采用重载函数模板,但在进行程序设计时,仍然应当尽量少地使用,以避免不小心带来的二义性。
实例演示函数模板重载
下面的例子展示了函数模板重载的一种应用:#include <iostream> #include <string> // 基本模板 template <typename T> void display(T value) { std::cout << "Basic template: " << value << std::endl; } // 重载1:接受两个参数的版本 template <typename T> void display(T value1, T value2) { std::cout << "Overloaded template with two parameters: " << value1 << ", " << value2 << std::endl; } // 重载2:接受一个std::string和一个T类型的参数 template <typename T> void display(std::string message, T value) { std::cout << message << ": " << value << std::endl; } int main() { int a = 1; double b = 2.0; std::string str = "Hello"; // 使用基本模板 display(a); // 使用接受两个参数的重载版本 display(a, a); // 使用接受一个std::string和一个T类型的参数的重载版本 display("Custom message", a); return 0; }输出结果为:
Basic template: 1
Overloaded template with two parameters: 1, 1
Custom message: 1
- 一个基本的模板,接受一个类型为 T 的参数;
- 一个接受两个类型为 T 的参数的重载版本;
- 一个接受一个 std::string 和一个类型为 T 的参数的重载版本。
在 main() 函数中,我们对这些不同版本的 display() 函数进行了调用,以展示函数模板重载的工作方式。