泛型编程
编写与类型无关的通用代码,是代码复用的一种手段,模板是泛型编程的基础
模板
函数模板
函数怒班代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本
template<typename T1, typename T2, ..., typename Tn>
返回值类型 函数名(参数列表){}
//typename是定义模板的关键字,也可以使用class,不能用struct
模板不是函数,是编译器产生特定具体类型函数的模具,在编译阶段,编译器需要根据传入的实参类型来推演生成对应类型的函数
函数模板实例化
- 隐式实例化:编译器根据实参推演模板参数的实际类型,在模板中,编译器不会进行类型转换,所以同一个参数T的类型必须相同
- 显式实例化:在函数名后的<>中指定模板参数的实际类型,如果不匹配,编译器会进行隐式转换,转换失败编译器将会报错
- 非函数模板可以和同名的函数模板同时存在,该函数模板可以被实例化为这个非函数模板
- 非函数模板与其同名的函数模板,编译器在调用时会优先调用非函数模板,如果函数模板可以产生一个具有更好的品牌函数,那么调用函数模板
- 函数模板不允许类型转换,普通函数可以进行类型转换
类模板
template<class T1, class T2, ..., class Tn>
class 类模板名{};
//类模板中的函数放在类外进行定义时,需要加模板参数列表
在类模板名后的<>中指定模板参数的实际类型,类模板名字不是真正的类,实例化的结果才是真正的类
模板参数
- 类型形参:在参数列表中用class或typename修饰的参数类型
- 非类型形参:用常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用,非类型模板参数必须在编译时期确认结果,浮点数、类对象、字符串不允许作为非类型模板参数
模板特化
在原模板的基础上,对特殊类型进行特殊化称为模板特化,模板特化分为函数模板特化和类模板特化
template<class T>
bool IsEqual(T& left, T& right){}
template<>
//函数形参表必须和函数模板的基础参数类型相同,如果不同编译器可能会报错
bool IsEqual<char*>(cahr*& left, char*& right){}
bool IsEqual(cahr* left, char* right){}
template <class T1, class T2>
class Data{};
template <>
class Data<char, int>{};
template <class T1>
class Data<T1, int>{};
//偏特化为指针类型
template <class T1, class T2>
class Data<T1*, T2*>{};
//偏特化为引用类型
template <class T1, class T2>
class Data<T1&, T2&>{};