首页 > 编程笔记

C++函数模板的重载

和普通函数一样,函数模板也可以重载。重载的函数模板,模板名称相同,但函数形参列表不同。

例如:
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

在这个例子中,display() 函数有以下几种不同的模板重载:
在 main() 函数中,我们对这些不同版本的 display() 函数进行了调用,以展示函数模板重载的工作方式。

推荐阅读