目录
1.非类型模板参数
2.模板的特化
1.非类型模板参数
我们知道,模板一般是不指定类型的,具体是什么类型由其他部分的代码的决定。
模板参数分为类型模板参数和非类型模板参数。
类型形参即:出现在模板参数列表中,跟在class或者typename之后的参数类型名称。
非类型形参:就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用。
// 定义一个模板类型的静态数组template<class T, size_t N = 10>class array{public:T& operator[](size_t index){return _array[index];}const T& operator[](size_t index)const{return _array[index];}size_t size()const{return _size;}bool empty()const{return 0 == _size;}private:T _array[N];size_t _size;};
浮点数、类对象以及字符串是不允许作为非类型模板参数的。C++20目前似乎支持。
2.模板的特化
特化即特殊处理的意思。
先来看一个例子:
// 函数模板 -- 参数匹配 template<class T> bool Less(T left, T 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 = &d1;Date* p2 = &d2;cout << Less(p1, p2) << endl; // 可以比较,结果错误return 0; }
错误的原因就是因为这里比较的是地址的大小。要想避免这种情况发生,对模板特化。
// 函数模板 -- 参数匹配 template<class T> bool Less(T left, T right) {return left < right; } // 对Less函数模板进行特化 template<> bool Less<Date*>(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 = &d1;Date* p2 = &d2;cout << Less(p1, p2) << endl; // 调用特化之后的版本,而不走模板生成了return 0; }
但一般都是直接给出这个函数。
bool Less(Date* left, Date* right) {return *left < *right; }
上面是函数模板特化的情况。
来看看类模板:
第一种情况称为全特化,也就是把模板参数全部给出。
要注意,特化是在原有模板存在的基础上添加的东西,你可能觉得把模板参数全部给出不如直接写一个这样的类,但是特化!特化就是特殊处理模板不能直接实例化的这种类而做的处理。
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:int _d1; char _d2; }; void TestVector() {Data<int, int> d1;Data<int, char> d2; }
第二种情况称为偏特化,也有的说法叫半特化,这种用法挺有意思的。
先来看看普通的偏特化:
template<class T1, class T2> class Data { public:Data() {cout<<"Data<T1, T2>" <<endl;} private:T1 _d1;T2 _d2; }; // 将第二个参数特化为int template <class T1> class Data<T1, int> { public:Data() {cout<<"Data<T1, int>" <<endl;} private:T1 _d1;int _d2; };
这种情况大家都容易想到,来看看下面这种,挺有意思的
template<class T1, class T2> class Data { public:Data() {cout<<"Data<T1, T2>" <<endl;} private:T1 _d1;T2 _d2; }; //两个参数偏特化为指针类型 template <typename T1, typename T2> class Data <T1*, T2*> { public:Data() {cout<<"Data<T1*, T2*>" <<endl;}private:T1 _d1;T2 _d2; };
比如:
#include<vector> #include <algorithm> template<class T> struct Less {bool operator()(const T& x, const 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*>());return 0; }
全特化后:
// 对Less类模板按照指针方式特化 template<> struct Less<Date*> {bool operator()(Date* x, Date* y) const{return *x < *y;} };