模板,即是一种泛型编程,包扩类模板和函数模板。实际上就是为了类或函数的通用性,将类型参数化。
1.函数模板实现方式:
template<typename T>
void fun(T data){}
关键字template总放在模板定义的最前面。关键字后面是模板参数列表,与函数参数列表类似,不同之处在于用尖括号(<>)括起来,且不能为空。 模板参数可以是模板类型参数(一种类型),也可以是模板非类型参数(一个常量表达式)。如:
template<typename T,char ch,int size...> //非模板类型参数可以为指针,但不可用double和flout
模板参数类型的参数由关键字class或typename后加个标识符构成,
两个关键字意义相同,可任意使用。但这里的class和类定义中的class要分清。
标识符为任意字母组合,但一般用T或C,它代表一个内置的或用户自定义的类型(
当它是指针类型时要注意const的修饰)
。
小知识点:
(1)如果在全局域中声明了模板参数同名的对象、函数或类型,则该全局名将被隐藏。
(2)在函数模板定义中声明的对象或类型不能与模板参数同名。
(3)模板参数名在同一模板参数表中只能被使用一次,但模板参数名可以在多个函数模板或定义之间被重复使用。
(4)一个模板的定义和多个声明所使用的模板参数名无需相同。
(5)函数模板也可以被声明为inline或extern,指示符放在参数表后面,函数定义前面。
2.函数模板的实例化:
函数模板在未实例化前相当于一个类型,是不进行编译的。只有在模板实例化时才会进行编译。
(1)隐式实例化:通过函数调用的方式实例化函数模板的过程被称为模板实参推演。
template<typename T,char ch,int size...> //非模板类型参数可以为指针,但不可用double和flout
(2)显示实例化:提前指定模板,实例化一份
//显示实例化:
template void fun<int>(int a);
(3)提前声明:
template<typename T>
void fun(T a);
模板函数:函数模板实例化后的函数。(4)函数模板推演:
①根据参数类型
②不可有二异性
3.模板的特例化:计算机实例化过程中会出现逻辑错误的。如:
template<>
void fun<char *>(char * a){}
4.调用顺序:
优先调用非模板函数 ->特例化的->通过模板实例化的 -> 特例化优化类型 -> 报错
5.函数模板的重载
// 类模板 Array 的定义
template <typename Type>
class Array{ /* ... */ };
// min() 的三个函数模扳声明
template <typename Type>
Type min( const Array<Type>&, int ); // #1
template <typename Type>
Type min( const Type*, int ); // #2
template <typename Type>
Type min( Type, Type ); // #3
注意:成功的声明一组重载函数模板并不能保证它们可以被成功的调用。在调用一个模板实例时,重载的函数模板可能会导致二义性。如:
template <typename T>
int min( T, T ) { /* ... */ }
template<typename T,typename U>
int min(T,U){ /*...*/ }
这两个模板函数是重载的,但当调用时为(int,int)的相同类型参数的调用时,两个函数模板都可以实例化,这时就产生了二义性。因为min(T,U)处理的调用集是min(T,T)处理的超集,所以应该保留min(T,U)的函数模板,删除min(T,T)的函数模板。