非类型模板参数
模板参数分类类型形参与非类型形参。
类型形参即:出现在模板参数列表中,跟在class
或者typename
之类的参数类型名称。
非类型形参,就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用。
template<class T,size_t n>
class test
{
private:
T array[n];
};
int main()
{
array(int,10)nums1;
array(int,20)nums2;
}
- 浮点数、类对象以及字符串是不允许作为非类型模板参数的。
- 非类型的模板参数必须在编译期就能确认结果。
主要针对的的是int
类型的非模板类型特化。
类模板的特化
通常情况下,使用模板可以实现一些与类型无关的代码,但对于一些特殊类型的可能会得到一些错误的结果,比如:
template<class T>
class Compare
{
bool isepual(const char* x1,const char* x2)
{
return strcmp(x1,x2);
}
};
void test()
{
const char* p1="hello";
const char* p2="janson";
isepual(p1,p2);
}
此时,就需要对模板进行特化。即:在原模板类的基础上,针对特殊类型所进行特殊化的实现方式。模板特化中分为函数模板特化与类模板特化。
函数模板特化
- 函数模板的特化步骤:
-
- 必须要先有一个基础的函数模板
-
- 关键字template后面接一对空的尖括号<>
-
- 函数名后跟一对尖括号,尖括号中指定需要特化的类型
-
- 函数形参表: 必须要和模板函数的基础参数类型完全相同,如果不同编译器可能会报一些奇怪的错误。
将之前的代码就可以修改成如下代码:
template<>
bool IsEqual<char*>(char*& left, char*& right)
{
if(strcmp(left, right) > 0)
return true;
return false;
}
将template尖括号中的参数为空,在函数名或者类名后加所要特化的类型。
类模板特化
全特化
全特化即是将模板参数列表中所有的参数都确定化
template
class Data(double,int)
{
public:
Data()
{cout<<"Data<double, int>" <<endl;}
private:
T1 _d1;
T2 _d2;
}
偏特化
部分特化
template<class T1>
class date(T1,int)
{
public:
date()
{
cout<<"T1,int"<<endl;
}
private:
T1 d1;
int d2;
}
参数更进一步的限制
类似于如果之前是T1,T2在特化的时候就可以指定传入T1&,T2&这样就是对参数进一步的限制。
分离编译
什么是分离编译
一个程序(项目)由若干个源文件共同实现,而每个源文件单独编译生成目标文件,最后将所有目标文件链接起来形成单一的可执行文件的过程称为分离编译模式。
模板的分离编译
原因及其分析
如果分离编译这里要注意的是当我们进行链接的时候,会报连接错误,因为模板声明了之后,如果未使用就不会进行实例化,当我们对其进行使用时date(1,2)
这里才回去实例化模板,此时就会造成两种结局,在声明那里不知道你要传进来的类型,在使用的时候没有办法找到定义的函数,兵不识将,将不识兵的局面
解决方法
- 将声明和定义放到一个文件 “xxx.hpp” 里面或者xxx.h其实也是可以的。推荐使用这种。
- 模板定义的位置显式实例化。这种方法不实用,不推荐使用.
模板总结
-【优点】
- 模板复用了代码,节省资源,更快的迭代开发,C++的标准模板库(STL)因此而产生
- 增强了代码的灵活性
-【缺陷】
- 模板会导致代码膨胀问题,也会导致编译时间变长
- 出现模板编译错误时,错误信息非常凌乱,不易定位错误