1. 模板参数分类
模板参数分成两种:
一种是 非类型形参 和 类型形参
类型形参:
举例
template<class T> struct less { bool operator()(const T& x, const T& y) { return x > y; } };
非类型形参:
举例
template<size_t x> class arry { private: int _arr[x]; };
这里数组的大小可以被固定住,取决于 x
注意:
- 非类型形参,就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量(不可以被修改)来使用 ,常量是整型类型(如:size_t ,int ,long , char 等等)
- 非类型的模板参数必须在编译期就能确认结果
2. 模板的特化
对于某些特殊的类型,使用模板可能会得到一些的错误的结果
如:日期类的比较
举例
#include<iostream>
using namespace std;
template<class T>
bool less(const T x, const T y)
{
return x > y;
};
int main()
{
Data t1(2024,3,6);
Data t2(2021,6,7);
cout << less(t1,t2) << endl; //这种比较得到的是正确的
Data* p1 = new Data(2024,3,6);
Data* p2 = new Data(2021,6,7);
cout << less(p1,p2) << endl; //这种比较结果不一定正确
}
分析:
p1 和 p2 都是动态开辟出来的空间,实际上 less 比较的是它们的地址的高低
a. 函数模板特化
函数模板的特化步骤:
1. 必须要先有一个基础的函数模板
2. 关键字template后面接一对空的尖括号<>
3. 函数名后跟一对尖括号,尖括号中指定需要特化的类型
4. 函数形参表: 必须要和模板函数的基础参数类型完全相同,如果不同编译器可能会报一些奇怪的错误
代码举例
template<class T> bool less(const T x,const T y) { return x > y; }; template<> bool less<Data *>(const Data *x,const Data *y) { return *x > *y; };
注意:
一般情况下如果函数模板遇到不能处理或者处理有误的类型,为了实现简单通常都是将该函数直接给出
代码举例
bool less(const Data *x,const Data *y) { return *x > *y; };
这样的代码的可读性高,容易书写,因为对于一些参数类型复杂的函数模板,特化时直接给出,因此函数模板不建议特化
b. 类模板特化
(1)全特化
全特化即是将模板参数列表中所有的参数都确定化
代码举例
template<class T1, class T2> class AA { public: AA() { cout << "T1 T2" << endl; } private: T1 _a; T2 _b; }; template<> class AA<int,char> { public: AA() { cout << "int char" << endl; } private: int _a; char _b; }; void test2() { AA<int, int> t1; AA<int, char> t2; }
运行结果:
(2)偏特化
偏特化有两种:
一种是 部分特化: 将模板参数类表中的一部分参数特化
代码举例
template<class T1, class T2> class AA { public: AA() { cout << "T1 T2" << endl; } private: T1 _a; T2 _b; }; template<class T1> class AA<T1,char> { public: AA() { cout << "T1 char" << endl; } private: T1 _a; char _b; }; void test2() { AA<int, int> t1; AA<int, char> t2; }
运行结果:
另一种是 参数更进一步的限制
代码举例
template<class T1, class T2> class AA { public: AA() { cout << "T1 T2" << endl; } private: T1 _a; T2 _b; }; template<class T1,class T2> class AA<T1*,T2*> // 限制 T1,T2 是指针类型 { public: AA() { cout << "T1* T2*" << endl; } private: T1* _a; T2* _b; }; void test2() { AA<int, int> t1; AA<int*, char*> t2; }
运行结果:
注意:
特化必须在原模板的基础之上,它不是全新的模板
3. 模板分离编译
模板不支持分离编译(声明和定义不在一个文件)
a. 失败原因
分析原因:
预处理阶段:
头文件展开,去掉注释,替换宏,条件编译
编译:
检查语法,生成汇编代码(一串指令)
汇编:
将汇编代码转换成二进制机器码
链接:
合成生成可执行文件
由此我们直到,在编译的时候,无法实例化模板,因为模板参数的类型是无法确定的,也无法生成汇编代码
b. 解决方案
声明和定义都放在同一个.h文件中
代码举例
test.h
namespace lhy { template<class T> class Add { public: Add() :x(T()) , y(T()) {} int add(); private: T x; T y; }; template<class T> int Add<T> ::add() { return x + y; } }
test.cpp
using namespace std; #include "test.h" int main() { lhy::Add<int> t; cout << t.add() << endl; }
运行结果:
4. 模板总结
【优点】
1. 模板复用了代码,节省资源,更快的迭代开发,C++的标准模板库(STL)因此而产生
2. 增强了代码的灵活性
【缺陷】
1. 模板会导致代码膨胀问题,也会导致编译时间变长
2. 出现模板编译错误时,错误信息非常凌乱,不易定位错误