目录
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; } };