模板解析
模板的意义:对类型进行参数化(允许将类型当做参数传递)
函数模板
函数模板:template<typename T> bool compare(T a, T b)不进行编译
这就是为什么模板不能在一个文件中定义,在另一个文件中声明并使用的原因:模板本身不编译,模板代码在调用前必须看见模板定义的位置,才会正常实例化,否则会产生编译错误
模板的实例化:在函数调用点处进行实例化
模板函数:经过编译实例化出来的函数
模板类型参数:typename 或 class 定义出来的参数
模板的非类型参数:必须是整数类型(int,地址,引用)都只能作为常量使用,比如template<typename T, int SIZE>里的SIZE就是一个非类型参数
模板的特例化:提供某些类型的特例化版本,比如template<> bool compare<const char*>(const char* a, const char* b){}提供const char*类型的特例化版本
有完全特例化版本会优先匹配完全特例化,然后再寻找有无部分特例化版本,如果都没有才会自己生成
-
完全特例化:
//针对char*类型提供的完全特例化 template<> class Vector<char*>{ public: Vector() { } }; -
部分特例化:
//针对指针类型的部分特例化版本 template<typename Ty> class Vector<Ty*>{ public: Vector(){} }
在调用模板函数的时候
-
如果写
compare<int>(10,20);此时编译器会把compare<int>处理为函数名,直接去寻找模板,并在该调用点的位置,编译器会用用户指定的类型,从原模板实例化一份函数代码出来实际上每个实例都对应了一个函数代码,只是从编程者的角度来说代码量减少了
-
如果写
compare(10,20);,编译器会优先把compare处理为函数名字,寻找是否有可调用的非模板函数;如果没有找到的话,再进行实参推演,寻找相应的模板
类模板
类名 = 模板名称+类型参数列表,除了构造和析构函数名不需要加,其他出现模板的地方都要加上类型参数列表,比如在类外实现函数,需要添加的类作用域为类名<T>,比如template<typename T> void SeqStack<T>::push(const T &val)
类模板的选择性实例化:即类模板中的成员方法,只会在实际调用的时候才会实例化那些成员函数
泛型算法 = template + 迭代器 + 函数对象
特点一:泛型算法的参数接收的都是迭代器,目的是为了让所有容器都能使用泛型算法
特点二:泛型算法的参数也可以接受函数对象