模板
概念
模板的作用是实现类型通用,降低代码的冗余度
模板可以为一种算法定义不同类型的版本
实现机制:
使用类型参数突破类型的限制,丧失一定的类型安全
模板需要实例化才能使用,实例化由编译器完成
模板的分类
函数模板
函数模板就是带类型参数的函数,函数的返回值,形参,局部变量都可以使用类型参数,函数模板支持类型推断(形参)。
函数模板 -----> 实例化 -----> 函数
编译
类模板
类模板就是带类型参数的类,类的成员变量,成员函数.......可以使用类型参数,类模板不支持类型推断。
类模板 -----> 实例化 -----> 类 -----> 实例化 -----> 对象
编译 运行
模板的使用
函数模板
语法:
//函数模板的声明
template<typename T/*类型参数*/.....>
返回值类型 函数模板名(形参列表)
{
.......//可以使用T作为类型
}
//函数模板的调用
函数模板名<类型...>(实参);
//如果函数模板的类型参数可以通过实参来判断,传递的类型可以省略
练习:
使用函数模板实现一个数组的排序,实现数组元素类型的通用
void mysort(int *arr,int n);
类模板
语法:
//类模板的声明
template <typename T/*类型参数*/...>
class 类模板名{
//...类中可以直接使用T类型
};
//类模板的使用
类模板名<类型...> 对象;
//类模板不支持类型推断
模板的特化
如果模板第某些特殊类型的行为需要重新定义,此时可以进行模板的特化。
函数模板的特化
语法:
template <>
返回值类型 函数模板名<特化类型...>(参数列表)
{
//......重定义特化类型的行为
}
//编译器在对函数模板实例化时,如果有特化模板,有限选择特化的模板实例化
//函数模板不允许特化一部分参数,必须全特化
类模板的特化(全类特化)
语法:
template <>
class 类模板名<特化类型...>{
//...类中的内容重定义位特化类型的行为
};
练习:
为排序类模板实现const char *的特化
类模板的成员特化
对于类模板而言,既可以进行全类特化,也可以只针对部分与特化类型相关的成员函数进行特化。成员函数特化时要保持特化接口和原通用模板一致。
语法:
//类外进行成员特化
template <>
返回值类型 类模板名<特化类型...>::成员函数名(形参列表)
{
//......使用特化类型重定义函数的行为
}
类模板的局部特化
针对有多个类型参数的类模板,可以只特化其中一部分参数,编译器优先选择特化程度最高的版本。
特化一部分参数
template <T1,T2,T3>
class xxx{...}
//局部特化
template <T1,T2>
class xxx<T1,T2,int>{...}
template <T1>
class xxx<T1,double,int>{...}
xxx<char,double,int> a; ------ 选择第三个版本进行实例化
xxx<char,long,int> b; ------- 选择第二个版本进行实例化
xxx<char,long,float> c; ------ 选择第一个版本进行实例化
//对于有多个类型参数的类模板,可以对部分参数进行特化
//编译器优先选择特化程度最高的版本
特化类型参数之间的关系
template <T1,T2,T3>
class xxx{...}
//局部特化
template <T1,T2>
class xxx<T1,T2,T2>{...}
template <T1>
class xxx<T1,T1,T1>{...}
//对于有多个类型参数的类模板,可以对类型参数的关系进行特化
//编译器优先选择特化程度最高的版本
针对指针和数组类型的特化
template <T1,T2,T3>
class xxx{...}
//局部特化
template <T1,T2,T3>
class xxx<T1*,T2*,T3*>{...}
template <T1,T2,T3>
class xxx<T1[],T2[],T3[]>{...}
//对于有多个类型参数的类模板,可以针对指针和数组类型进行特化
//编译器优先选择特化程度最高的版本
作业:
1.使用函数模板和类模板(函数对象)实现二分查找,同时为函数模板实现const char *的特化,类模板实现const char *的成员(查找的成员函数)特化。