如果我们希望写一个函数实现比较两个数值的大小,相等则返回0,较小返回-1,较大返回1,可能会写如下的函数:
1 int compare(const string &v1, const string &v2) { 2 if(v1 < v2) return -1; 3 if(v2 < v1) return 1; 4 return 0; 5 }
虽然我们可以传入不同的参数,但是由于参数类型是固定的,所以只能传入int类型的值,如果想比较double或其他类型的值,就得写一个其他类型的重载版本:
1 int compare(const double &v1, const double &v2) { 2 if(v1 < v2) return -1; 3 if(v2 < v1) return 1; 4 return 0; 5 }
我们注意到这两个版本的实现除了类型其他都一样。如果为了适配不同的类型而创建具有同样实现的重载函数,不仅难以维护,而且违反了DRP(Don't repeat yourself)原则。那有没有一种方法,创建方法的时候只创建一次,但是又能处理任何类型(预知或不可预知的)的参数。
在C++中,我们可以使用模板来实现该功能。模板,他既不是类也不是函数,就像字面意思一样,只是一个模具,相当于一个公式,是C++支持参数化多态的工具。在经过编译器编译过后,最终还是生成一大堆类型不同的相似函数或类,只不过编译器帮我们做了繁杂的处理。
1.1 函数模板
由此定义一个compare的函数模板,先写模板关键字template, 紧接着尖括号,括号内使用关键字typename/class, 表明T是模板类型。
注意: 模板参数列表不能为空
注意:typename 和 class 实际没有区别。只是class先被引入到语言中。 然而,更建议使用 typename ,因为它更清楚地表明模板类型可以被任何类型(例如基本类型)替换,而不仅仅是类类型。
1 template<typename T> 2 int compare(const T &v1, const T &v2) { 3 if(v1 < v2) return -1; 4 if(v2 < v1) return 1; 5 return 0; 6 }
实例化函数模板
函数模板并不是函数,但是它只生成函数。
1 #include <iostream> 2 3 template <typename T> 4 int compare(const T &v1, const T &v2) { 5 if (v1 < v2) return -1; 6 if (v2 < v1) return 1; 7 return 0; 8 } 9 10 int main() { 11 std::cout << compare(1, 0) << std::endl; //-->int compare(const int &v1, const int &v2) 12 return 0; 13 }
当编译器遇到compare(1, 0)时,如果没有发现匹配的compare(int, int)的函数定义,就会使用compare<T>函数模板来创建一个参数类型为int的compare函数。
从函数模板创建函数的过程就叫实例化。
模板类型参数与非类型模板参数
compare函数中有一个模板类型参数T, 不仅可以表示类型说明符, 还可以指定返回类型或函数参数类型,以及函数体内的变量声明或类型转换。