模板进阶文章目录模板进阶1.非类型模板参数举例array2.函数模板的特化2.1引出特化示例更推荐将特化改成函数2.2格式2.3特化的问题一步一步说3.类模板的特化格式种类注意点4.模板声明定义分离问题为什么模版不建议显示实例化1.非类型模板参数类型模板参数template里面是class/typename这种templateclassT,classContainerstd::vectorT,classCompareLessTclasspriority_queue{。。。。。}举例只传参数不赋值templatesize_t N10,boolflagfalseclassStack{private:int_a[N];int_top;};intmain(){Stacks0;Stack5s1;Stack10s2;return0;}注意只用于整形家族char intlong‼️bool‼这种c20后面支持了double必须在编译期就能确定结果给了非类型模板参数 缺省值不能直接不加就创建——必须要Stack s0;这样写c 后面支持了array其实用vector更好不过array是栈上vector是堆上c的代替C语言数组的一个数据结构用法arrayint, 100 a1arraydouble, 10 a2好处越界检查更方便2.函数模板的特化不建议用2.1引出下面的代码没有对指针的比较问题// 函数模板 -- 参数匹配templateclassTboolLessFunc(T left,T right){returnleftright;}intmain(){coutLessFunc(1,2)endl;// 可以比较结果正确Dated1(2022,7,7);Dated2(2022,7,8);coutLessFunc(d1,d2)endl;// 可以比较结果正确Date*p1d1;Date*p2d2;coutLessFunc(p1,p2)endl;// 可以比较结果错误❌return0;}特化示例templateclassTboolLessFunc(T left,T right){returnleftright;}templateboolLessFuncDate*(Date*left,Date*right){return*left*right;}更推荐将特化改成函数当然特化和函数也可以同时存在不过还是会调用函数因为特化还是模板使用时会实例化麻烦templateclassTboolLessFunc(T left,T right){returnleftright;}boolLessFunc(Date*left,Date*right){return*left*right;}2.2格式templateboolLessFuncDate*(Date*left,Date*right){return*left*right;}必须要先有一个 函数模板然后创造一个相似的函数模板区别如下空的 关键字 template 后面 尖括号 是空的**再加**函数名后跟一对尖括号尖括号中指定需要特化的类型**形参相同**必须要和模板函数的基础参数类型完全相同2.3特化的问题一步一步说引出前面的模板写的不是很好为防止拷贝构造应该把T都改成const T ——templateclassT//bool LessFunc(T const left, T const right)boolLessFunc(constTleft,constTright){returnleftright;}但是特化就对不上了——改一下特化为boolLessFunc(constDate*left,constDate*right){return*left*right;}‼️这时候是错的原因注意看const Date* leftconst是在*前面——left指向的内容不能改变而left可变——和模板中的const T left对不上了——应该写成boolLessFunc(Date*constleft,Date*constright){return*left*right;}所以更推荐写成“和普通函数的重载”3.类模板的特化相当于是模板的重载——就像函数重载一样类型不同调用的模板/函数虽然重名但不是一个格式特化类模板的书写必须要先有一个 类模板然后创造一个相似的函数模板区别如下template后的中内容不确定‼️**class 类名后加**函数名后跟一对尖括号尖括号中指定需要特化的类型特化类模板的实例化类模板名尖括号其中有对应的类型类名例如Dataint, double d9;种类无特化templateclassT1,classT2classData{};全特化如果实例化时的两个类型和如下特化模板相同就调用对应的全特化模板templateclassDataint,char{};偏特化/半特化如果实例化时对应位置的类型符合就调用对应的偏特化模板templateclassT1classDataT1,double{};传指针的特殊偏特化实例化时中是指针类型templatetypenameT1,typenameT2classDataT1*,T2*{};传引用的特殊偏特化实例化时中是引用类型templatetypenameT1,typenameT2classDataT1,T2{};注意点实例化时中的内容如果传的是*指针或引用在偏特化类模板中对应的内容是原类型‼️⬇️对于他俩以及他俩的混合——第三列传指针的特殊偏特化传引用的特殊偏特化既有传指针又有传引用偏特化的写法template typename T1, typename T2class Data T1*, T2*{};template typename T1, typename T2class Data T1, T2{};template typename T1, typename T2class Data T1, T2*{};实例化Dataint*, char* d7;Dataint, double d9;Dataint, int* d10;T1和T2的实际指代T1是intT2是charT1是intT2是doubleT1是intT2是inttemplateclassT1,classT2classData{public:Data(){coutDataT1, T2endl;}private:T1 _d1;T2 _d2;};// 全特化templateclassDataint,char{public:Data(){coutDataint, charendl;}};// 偏特化/半特化templateclassT1classDataT1,double{public:Data(){coutDataT1, doubleendl;}};templateclassT1classDataT1,char{public:Data(){coutDataT1, charendl;}};// 偏特化传的类型是指针templatetypenameT1,typenameT2classDataT1*,T2*{public:Data(){coutDataT1*, T2*endl;}};templatetypenameT1,typenameT2classDataT1,T2{public:Data(){coutDataT1, T2endl;}};templatetypenameT1,typenameT2classDataT1,T2*{};4.模板声明定义分离问题为什么模版不建议➡️有关 编译链接预处理 的知识可以点击这里进行学习⬅️答先假设有3个文件func.hfunc.cppmain.cpp声明和定义分离在func.h中声明func.cpp定义main.cpp中使用的情况虽然有声明和定义但是func.cpp中没有使用➡️没有实例化➡️没有函数生成‼️main.cpp编译的时候即使把.h复制进来也无法找到函数❌声明、定义部分离都在func.h中main.cpp中使用的时候有定义➡️实例化出函数✅➡️豆包的详细解释可以点击这里进行学习⬅️显示实例化用来实现模板的声明定义分离写法templateintaddint(int,int);直接一个template后面什么也不加下面写函数函数名后面写尖括号里面写类型**原因**写这一行强制生成 int 版本链接就能找到。使用频率日常几乎不用只用来强行实现分离编译。之前在模板初阶的时候也讲了一个显示实例化和这个不是一回事原来的显示实例化调用侧手动告诉编译器 T 是什么。当编译器无法推导出模板参数类型时必须用Addint(a1,d1);// 强制T为intAdddouble(a1,d1);// 强制T为doubletemplateclassTT*func1(intn){returnnewT[n];}intmain(){double*p1func1double(10);//当编译器无法推导出模板参数类型时必须用显式实例化return0;}
C++模板进阶从非类型参数到特化全解,避开90%人踩过的坑,面试再也不怕模板题!
模板进阶文章目录模板进阶1.非类型模板参数举例array2.函数模板的特化2.1引出特化示例更推荐将特化改成函数2.2格式2.3特化的问题一步一步说3.类模板的特化格式种类注意点4.模板声明定义分离问题为什么模版不建议显示实例化1.非类型模板参数类型模板参数template里面是class/typename这种templateclassT,classContainerstd::vectorT,classCompareLessTclasspriority_queue{。。。。。}举例只传参数不赋值templatesize_t N10,boolflagfalseclassStack{private:int_a[N];int_top;};intmain(){Stacks0;Stack5s1;Stack10s2;return0;}注意只用于整形家族char intlong‼️bool‼这种c20后面支持了double必须在编译期就能确定结果给了非类型模板参数 缺省值不能直接不加就创建——必须要Stack s0;这样写c 后面支持了array其实用vector更好不过array是栈上vector是堆上c的代替C语言数组的一个数据结构用法arrayint, 100 a1arraydouble, 10 a2好处越界检查更方便2.函数模板的特化不建议用2.1引出下面的代码没有对指针的比较问题// 函数模板 -- 参数匹配templateclassTboolLessFunc(T left,T right){returnleftright;}intmain(){coutLessFunc(1,2)endl;// 可以比较结果正确Dated1(2022,7,7);Dated2(2022,7,8);coutLessFunc(d1,d2)endl;// 可以比较结果正确Date*p1d1;Date*p2d2;coutLessFunc(p1,p2)endl;// 可以比较结果错误❌return0;}特化示例templateclassTboolLessFunc(T left,T right){returnleftright;}templateboolLessFuncDate*(Date*left,Date*right){return*left*right;}更推荐将特化改成函数当然特化和函数也可以同时存在不过还是会调用函数因为特化还是模板使用时会实例化麻烦templateclassTboolLessFunc(T left,T right){returnleftright;}boolLessFunc(Date*left,Date*right){return*left*right;}2.2格式templateboolLessFuncDate*(Date*left,Date*right){return*left*right;}必须要先有一个 函数模板然后创造一个相似的函数模板区别如下空的 关键字 template 后面 尖括号 是空的**再加**函数名后跟一对尖括号尖括号中指定需要特化的类型**形参相同**必须要和模板函数的基础参数类型完全相同2.3特化的问题一步一步说引出前面的模板写的不是很好为防止拷贝构造应该把T都改成const T ——templateclassT//bool LessFunc(T const left, T const right)boolLessFunc(constTleft,constTright){returnleftright;}但是特化就对不上了——改一下特化为boolLessFunc(constDate*left,constDate*right){return*left*right;}‼️这时候是错的原因注意看const Date* leftconst是在*前面——left指向的内容不能改变而left可变——和模板中的const T left对不上了——应该写成boolLessFunc(Date*constleft,Date*constright){return*left*right;}所以更推荐写成“和普通函数的重载”3.类模板的特化相当于是模板的重载——就像函数重载一样类型不同调用的模板/函数虽然重名但不是一个格式特化类模板的书写必须要先有一个 类模板然后创造一个相似的函数模板区别如下template后的中内容不确定‼️**class 类名后加**函数名后跟一对尖括号尖括号中指定需要特化的类型特化类模板的实例化类模板名尖括号其中有对应的类型类名例如Dataint, double d9;种类无特化templateclassT1,classT2classData{};全特化如果实例化时的两个类型和如下特化模板相同就调用对应的全特化模板templateclassDataint,char{};偏特化/半特化如果实例化时对应位置的类型符合就调用对应的偏特化模板templateclassT1classDataT1,double{};传指针的特殊偏特化实例化时中是指针类型templatetypenameT1,typenameT2classDataT1*,T2*{};传引用的特殊偏特化实例化时中是引用类型templatetypenameT1,typenameT2classDataT1,T2{};注意点实例化时中的内容如果传的是*指针或引用在偏特化类模板中对应的内容是原类型‼️⬇️对于他俩以及他俩的混合——第三列传指针的特殊偏特化传引用的特殊偏特化既有传指针又有传引用偏特化的写法template typename T1, typename T2class Data T1*, T2*{};template typename T1, typename T2class Data T1, T2{};template typename T1, typename T2class Data T1, T2*{};实例化Dataint*, char* d7;Dataint, double d9;Dataint, int* d10;T1和T2的实际指代T1是intT2是charT1是intT2是doubleT1是intT2是inttemplateclassT1,classT2classData{public:Data(){coutDataT1, T2endl;}private:T1 _d1;T2 _d2;};// 全特化templateclassDataint,char{public:Data(){coutDataint, charendl;}};// 偏特化/半特化templateclassT1classDataT1,double{public:Data(){coutDataT1, doubleendl;}};templateclassT1classDataT1,char{public:Data(){coutDataT1, charendl;}};// 偏特化传的类型是指针templatetypenameT1,typenameT2classDataT1*,T2*{public:Data(){coutDataT1*, T2*endl;}};templatetypenameT1,typenameT2classDataT1,T2{public:Data(){coutDataT1, T2endl;}};templatetypenameT1,typenameT2classDataT1,T2*{};4.模板声明定义分离问题为什么模版不建议➡️有关 编译链接预处理 的知识可以点击这里进行学习⬅️答先假设有3个文件func.hfunc.cppmain.cpp声明和定义分离在func.h中声明func.cpp定义main.cpp中使用的情况虽然有声明和定义但是func.cpp中没有使用➡️没有实例化➡️没有函数生成‼️main.cpp编译的时候即使把.h复制进来也无法找到函数❌声明、定义部分离都在func.h中main.cpp中使用的时候有定义➡️实例化出函数✅➡️豆包的详细解释可以点击这里进行学习⬅️显示实例化用来实现模板的声明定义分离写法templateintaddint(int,int);直接一个template后面什么也不加下面写函数函数名后面写尖括号里面写类型**原因**写这一行强制生成 int 版本链接就能找到。使用频率日常几乎不用只用来强行实现分离编译。之前在模板初阶的时候也讲了一个显示实例化和这个不是一回事原来的显示实例化调用侧手动告诉编译器 T 是什么。当编译器无法推导出模板参数类型时必须用Addint(a1,d1);// 强制T为intAdddouble(a1,d1);// 强制T为doubletemplateclassTT*func1(intn){returnnewT[n];}intmain(){double*p1func1double(10);//当编译器无法推导出模板参数类型时必须用显式实例化return0;}