是一种自动生成代码的技术,这种技术能让程序员在编写代码时不需要过多地考虑数据类型,这种技术也称为泛型编程技术
C/C++是一种静态编程语言(预处理->编译->汇编->链接->可执行文件),静态编程语言缺点实现通用代码比较麻烦,优点是运行速度更快
例如 void* + 回调函数
void qsort(void *base, size_t nmemb, size_t size,int (*compar)(const void *, const void *));
base:待排序内存首地址
nmemb:待排序元素个数
size:待排序每个元素字节数
compar:回调比较函数 调用者提供
① 借助回调函数+void*实现通用版本,实现难度较高、使用比较麻烦
② 借助宏函数实现通用版本,类型检查不严格、没有返回值、容易二义性 swap
③ 借助函数重载实现通用版本,导致代码段增加,未知类型无法解决
④ 综上所述,C++之父在C++中增加了模板技术,从而让C++的编程尽量不受类型困扰
templateT3 函数名(T1 arg1,T2 arg2) {}
注意:未知类型名可以取任何名字,一般约定俗成使用T为名字
函数模板的template声明必须每个函数模板都要有
C++编译器不会把函数模板先生成一个函数实体,而是当编译时发生调用,才会生成具体版本的函数实体,这个过程称为函数模板的实例化
编译器自动根据实参类型生成该版本的函数实体
如果编译器无法自动根据实参类型获取所有未知类型的类型,那么就需要手动提供所有未知类型
函数名<类型名1,类型名2,类型名3>(实参1,实参2)
函数模板被调用时会经过两次编译
① 检查函数模板的语法是否有错误,此时编译结束后不会生成该函数的二进制指令
② 当编译到调用函数模板语句时,会再次根据调用者提供的实参类型编译函数模板,如果没有错误才会生成该版本的二进制指令存储在代码段,所有如果没有调用函数模板则不会生成具体的函数实体
这种方式称为函数模板的"惰性实例化"准则
templateT2 函数名(T1 arg1,T1 arg2){ }
函数模板的未知类型可以设置默认的参数类型,如果调用者没有提供具体的参数类型,那么按照默认参数类型来实例化函数,但是只有C++11语法标准才支持,需要增加编译参数 :
-std=gnu++11 或者 -std=c++0x
模板虽能解决绝大部分类型问题,但是不能解决所有类型的问题,有个别类型的处理方式与其他类型不同,因此需要给这些特殊类型实现一个特殊版本,该函数模板称为特化
template<> 返回值类型 函数名(特化类型名 形参名,...){}
注意:
① 特化外,还必须有一个基础的函数模板
② 必须加template<>,才算是函数模板特化,不然就是普通函数
③ 可以同时存在普通函数模板、函数模板特化、普通函数,如果类型匹配,优先调用普通函数,其次是特化版本,最后是普通函数模板
④ 普通函数无论是否调用都会生成二进制指令,函数模板、特化只有调用时才会生成,遵循"惰性实例化"准则
类模板:是一种使用了未知类型来设计类的技术
template
class Test
{
T1 num;
public:
Test(T1 num){}
Test(T2& that){}
R func(void) {}
};
必须实例化后类才会生成,也遵循"惰性实例化"原则
与函数模板不同的是,它不支持自动实例化,必须手动实例化
类名<类型名> 对象;
注意:使用了类模板后,所有使用到类名的位置,类名后必须加<合适的类型名>,否则编译器报错
类模板允许有静态成员
类模板和普通类的静态成员都需要在类外定义
template
class 类名
{
static 类型名 num;
};
template类型名 类名::num = 初始化;
template<>类型名 类名::num = 初始化;
类模板的静态成员变量在类模板定义时不会创建,是在类对象实例化时才会创建
而普通类的静态成员变量在程序运行前,无论是否实例化对象都会创建
Test t1,t2; //t1 t2共享同一个静态成员变量
Test c1,c2; //c1 c2共享同一个静态成员变量
// t c 之间的静态成员变量不同享
类模板的未知类型可以是任意合法类型,包括类模板类型
类名1<类名2<类型> > 对象; // >> 之间最好空格隔开
template
class A
{
T num;
};
template
class B{};
A > a;
当类模板中的个别成员函数无法支持所有类型时,可以针对特殊类型实现类模板中某个成员函数的特化,称为局部特化
template<> 返回值 类名<特殊类型>::成员函数(特殊类型 形参名){}
注意:类模板的局部特化函数要求特殊类型 与 类模板的原类型,除了类型名替换不一样外,其他属性(const * &)都必须完全相同,否则编译器报错
而且局部特化函数必须类外实现
if(typeid(T) == typeid(const char*))
{
if(0 == strcmp())
}
else
{
if(==)
}
为了一个特殊类类型实现整个类的特化,称为类的全局特化
template<>
class 类名<特殊类型>
{
// 重新实现该类
};