主要内容:
非类型模板参数;
类模板的特例化;
模板的分离编译;
一.非类型模板参数:
1.模板参数分为:类型形参和非类型形参;
类型形参:
出现在模板参数列表中的,跟在class或者typename之类的参数类型名称;
非类型形参:
用一个常量作为类模板参数,在类模板中可将该参数当成常量来使用;
关于非类型模板参数的代码演示:
#include <iostream>
using namespace std;
template <class T,size_t N>
class Array{
private:
T _a[N];
};
int main(){
Array<int,10> a;
Array<int,100>a;
return 0;
}
注意:
1.浮点数,类对象和字符串是不允许作为非类型模板参数的;
2.非类型的模板参数必须在编译期间就能确认结果;
二.模板的特化:
通常情况下使用模板可以实现一些与类型无关的代码,但对于特殊的类型可能会得到特殊的结果:
template<class T>
bool IsEqual(const T& left, const T& right){
return left == right;
}
int main(){
char* p1 = "hello";
char* p2 = "world";
if (IsEqual(p1,p1){
cout << p1 << endl;
}
else{
cout << p2 << endl;
}
因此就需要对模板进行特例化,即在原有的模板类的基础上,针对特殊类型所实现的特殊化的实现方式:
1.函数模板的特化:
步骤:
(1)先有一个基础的函数模板;
(2)关键字template后接一对空的尖括号<>;
(3)函数名后跟一对尖括号,尖括号中指定需要特化的类型 ;
(4)函数形参表: 必须要和模板函数的基础参数类型完全相同,如果不同编译器可能会报一些奇怪的错误;
template <>
bool IsEqual<char*>(char*& left, char*& right) {
if(strcmp(left, right) > 0)
return true;
return false;
}
2.类模板的特化:
(1)全特化:把模板参数类表中的所有参数都确定化;
template <class T1,class T2>
class Data {
public:
Data() {
cout<<"Data<T1, T2>" <<endl;
}
private:
T1 _d1;
T2 _d2;
};
template<>
class Data<int, char> {
public:
Data() {
cout<<"Data<int, char>" <<endl;
}
private:
T1 _d1;
T2 _d2;
};
void TestVector() {
Data<int, int> d1;
Data<int, char> d2;
}
(2)半特化:任何针对模版参数进一步进行条件限制设计的特化版本;
template <class T1>
class Data<T1, int> {
public:
Data() {
cout<<"Data<T1, int>" <<endl;
}
private:
T1 _d1;
int _d2;
};
将模板参数类表中的一部分参数特化;
//两个参数偏特化为指针类型:
template <typename T1, typename T2>
class Data <T1*, T2*> {
public:
Data() {
cout<<"Data<T1*, T2*>" <<endl;
}
private:
T1 _d1;
T2 _d2;
};
//两个参数偏特化为引用类型
template <typename T1, typename T2>
class Data <T1&, T2&> {
public:
Data(const T1& d1, const T2& d2)
: _d1(d1)
, _d2(d2)
{
cout<<"Data<T1&, T2&>" <<endl;
}
private:
const T1 & _d1;
const T2 & _d2;
};
void test () {
Data<double , int> d1; // 调用特化的int版本
Data<int , double> d2; // 调用基础的模板
Data<int *, int*> d3; // 调用特化的指针版本
Data<int&, int&> d4(1, 2); // 调用特化的指针版本
}
三.模板的分离编译:
1.分离编译的概念:一个程序(项目)由若干个源文件共同实现,而每个源文件单独编译生成目标文件,最后将所有目标文件链接起来形成单一的可执行文件的过程称为分离编译模式;
2.关于模板的分离编译:
模板不支持分离编译:
因为C/C++程序在编译的时候都需要进行一下过程:预处理----->编译------>汇编------->链接 ;
预处理的过程包括:去掉头文件,宏替换,去掉注释,条件编译;
编译的过程:对程序通过语言特性进行语法,词法,语意分析然后生成汇编代码;此时头文件不参与编译,编译器对工程中的多个源文件是分开进行编译的;
链接的过程:将多个obj文件合并成为一个,并处理没有解决的地址问题;
我们知道模板是根据实参类型产生特定的模板类型;如果将模板进行分离后,模板中的参数没有看到实参中的类型,因此不会产生具体的函数;而在main函数中函数进行调用时,编译器在连接时会找其地址,但函数没有实例化,没有生成具体代码,因此链接时会报错;
四.模板的优缺点总结:
模板的优点:
1.模板复用了代码,节省了资源,更快的迭代开发,C++的STL库也因此产生;
2.增强了代码的灵活性;
模板的缺点:
1.模板会导致代码膨胀的问题,也会导致编译时间过长;
2.出现模板编译错误时,编译信息会非常混乱,不易查找;