目录
3.array和原生数组比较——array唯一优势:有越界检查
一.容器array
1.介绍
固定长度的顺序容器,就是定长数组
2.array和vector比较
vector是动态开辟的,放在堆上的,且内部存的是指针;array就是个定长数组,放在栈上的,内部存的就是个数组
3.array和原生数组比较——array唯一优势:有越界检查
array相比原生数组唯一优势:有越界检查,因为有[]运算符重载,[]运算符重载中有assert检查。
4.总结建议:用vector别用array
array对比原生数组,还是有一些越界检查的优势的。但是实际中我们统一直接用vector更香!
5.非类型模板参数
(1)非类型模板参数是常量,不可修改
模板参数分类类型形参与非类型形参。
类型形参即:出现在模板参数列表中,跟在class或者typename之类的参数类型名称。
非类型形参,就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用。
(2)非类型模板参数一般就是整形。
整形int,char,unsigned int等。
1.浮点数、类对象以及字符串是不允许作为非类型模板参数的。
2.非类型的模板参数必须在编译期就能确认结果。
二.模板的特化
1.函数模板特化
函数模板的特化步骤:
1.
必须要先有一个基础的函数模板
2.
关键字
template
后面接一对空的尖括号
<>
3.
函数名后跟一对尖括号,尖括号中指定需要特化的类型
4.
函数形参表
:
必须要和模板函数的基础参数类型完全相同,如果不同编译器可能会报一些奇怪的错误。
template<class T>
bool Less(T left, T right) //模板函数
{
return left < right;
}
针对某些类型要特殊化处理
template<>
bool Less<Date*>(Date* left, Date* right) //模板特化
{
return *left < *right;
}
bool Less(Date* left, Date* right) //原生函数
{
return *left < *right;
}
函数模板基本不用特化方式处理,直接写一个具体类型的函数更好、
int main()
{
cout << Less(1, 2) << endl; // 可以比较,结果正确
Date d1(2022, 7, 7);
Date d2(2022, 7, 8);
cout << Less(d1, d2) << endl; // 可以比较,结果正确
Date* p1 = new Date(2022, 7, 16);
Date* p2 = new Date(2022, 7, 15);
cout << Less(p1, p2) << endl; // 可以比较,结果正确 3.
return 0;
}
正常的Less(d1, d2)比较日期类大小, 传进left < right后按照Date中的<运算符重载进行比较,但是Less(p1, p2)传的是指针,如果用模板函数会比较指针,所以这里用到模板特化函数去设置形参是Date*时比较*left < *right,类似于上面这种,就叫模板特化。当然也可以直接写出原生的函数,在没有原生函数的条件下,第3个Less(p1, p2)会优先调用模板特化函数,有原生函数会优先调用原生函数,在函数模板中是可以并存的,类模板中这样没法用。所以结论是:函数模板没必要特化,直接用原生函数就行
2.类模板特化
1.介绍
全特化即是将模板参数列表中所有的参数都确定化
半特化/偏特化 :
1、将模板参数类表中的一部分参数特化。
2、偏特化并不仅仅是指特化部分参数,而是针对模板参数更进一步的条件限制所设计出来
template<class T1, class T2>
class Data
{
public:
Data() { cout << "Data<T1, T2>" << endl; }
private:
T1 _d1;
T2 _d2;
};
// 全特化 :全特化即是将模板参数列表中所有的参数都确定化
template<>
class Data<int, double>
{
public:
Data() { cout << "Data<int, double>" << endl; }
};
// 半特化/偏特化 1:
// 1、将模板参数类表中的一部分参数特化。
template<class T1>
class Data<T1, char>
{
public:
Data() { cout << "Data<T1, char>" << endl; }
};
// 半特化的写法2:
// 2、偏特化并不仅仅是指特化部分参数,而是针对模板参数更进一步的条件限制所设计出来
//的一个特化版本。
template<class T1, class T2>
class Data<T1*, T2*>
{
public:
Data() { cout << "Data<T1*, T2*>" << endl; }
};
// 半特化的写法3:
template<class T1, class T2>
class Data<T1&, T2&>
{
public:
Data() { cout << "Data<T1&, T2&>" << endl; }
};
int main()
{
Data<int, int> d1;
Data<int, double> d2;
Data<int, char> d3;
Data<char, char> d4;
Data<int*, int*> d5;
Data<int*, char*> d6;
Data<int*, string*> d7;
Data<int*, void*> d8;
Data<int*, int> d9;
Data<int&, char&> d10;
return 0;
}
2.示例2:仿函数的偏特化使用
#include<vector>
#include <algorithm>
template<class T>
struct Less //模板函数
{
bool operator()(const T& x, const T& y) const
{
return x < y;
}
};
//template<> 这样写只能传Date*,所以不如干脆写个偏特化可以传任何指针类型
//struct Less<Date*>
//{
// bool operator()(Date* x, Date* y) const
// {
// return *x < *y;
// }
//};
// 偏特化
template<class T> //模板偏特化函数
struct Less<T*>
{
bool operator()(T* x, T* y) const
{
return *x < *y;
}
};
int main()
{
Date d1(2022, 7, 7);
Date d2(2022, 7, 6);
Date d3(2022, 7, 8);
vector<Date> v1;
v1.push_back(d1);
v1.push_back(d2);
v1.push_back(d3);
// 可以直接排序,结果是日期升序
sort(v1.begin(), v1.end(), Less<Date>());
vector<Date*> v2;
v2.push_back(&d1);
v2.push_back(&d2);
v2.push_back(&d3);
// 可以直接排序,结果错误日期还不是升序,而v2中放的地址是升序
// 此处需要在排序过程中,让sort比较v2中存放地址指向的日期对象
// 但是走Less模板,sort在排序时实际比较的是v2中指针的地址,因此无法达到预期
sort(v2.begin(), v2.end(), Less<Date*>());
vector<int*> v3;
v3.push_back(new int(3));
v3.push_back(new int(1));
v3.push_back(new int(2));
sort(v3.begin(), v3.end(), Less<int*>());
return 0;
}
v1使用模板函数,v2,v3使用模板偏特化函数。