多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

C++ 模板进阶(全)

C++ 模板进阶(全) 目录一. 非类型模板参数1.1 实例二. 模板的特化2.1 函数模板的特化2.1.1 实例2.1.2 函数模板的特化步骤2.2 类模板的特化2.2.1 全特化2.2.2 偏特化/半特化偏特化还可以特化指针和引用2.2.3 类模板特化应用实例三. 模板分离编译3.1 什么是分离编译3.2 模板的分离编译3.2.1 模板分离代码简单演示3.2.2 分析运行过程3.3 解决方法四. 模板总结4.1 模板的优点4.2 模板的缺点一. 非类型模板参数模板参数分类型形参与非类型形参。类型形参即出现在模板参数列表中跟在class或者typename之类的参数类型名称。非类型形参就是用一个常量作为类(函数)模板的一个参数在类(函数)模板中可将该参数当成常量来使用。1.1 实例templatesize_t N class Stack { private: int _a[N]; int top; };1. 浮点数、类对象以及字符串是不允许作为非类型模板参数的。2. 非类型的模板参数必须在编译期就确认结果。二. 模板的特化通常情况下使用模板可以实现一些与类型无关的代码但对于一些特殊类型的可能会得到一些错误的结果需要特殊处理比如实现了一个专门用来进行小于比较的函数模板。、2.1 函数模板的特化2.1.1 实例//普通函数模板 templateclass T bool Less(T left, T right) { return left right; } //特化模板 template bool LessDate*(Date* left, Date* right) { return left right; } int main() { Date d1(2026, 10, 6); Date d2(2026, 7, 4); cout Less(d1, d2) endl; Date* p1 d1; Date* p2 d2; cout Less(d1, d2) endl; return 0; }可以发现当类型是指针时我们原先的函数模板就无法发挥作用因为比较的就是地址了而不是里面的值那我们就可以对这个函数模板特化。但是实践中我们往往不写特化直接写现成的函数//普通函数模板 templateclass T bool Less(T left, T right) { return left right; } //现成的函数 bool Less(Date* left, Date* right) { return left right; } int main() { Date d1(2026, 10, 6); Date d2(2026, 7, 4); cout Less(d1, d2) endl; Date* p1 d1; Date* p2 d2; cout Less(d1, d2) endl; return 0; }对编译器来说有现成的函数就不会走模板的实例化这相当于是特化了。但是为什么不推荐使用函数模板的特化呢因为函数模板的特化有很大的坑。//普通函数模板 templateclass T bool Less(const T left,const T right) { return left right; } //特化模板 template bool LessDate*(Date* const left, Date* const right) { return left right; } int main() { Date d1(2026, 10, 6); Date d2(2026, 7, 4); cout Less(d1, d2) endl; Date* p1 d1; Date* p2 d2; cout Less(d1, d2) endl; return 0; }以防 T 是自定义类型我们通常会加上 const 和 来避免拷给构造但是 T 如果是指针我们就要注意 const 修饰的是整个指针也就是说 const 要放在 * 号后面来修饰指针本身。2.1.2 函数模板的特化步骤1、必须要先有一个基础的函数模板2、关键字template后面接一对空的尖括号;3、函数名后跟一对尖括号尖括号中指定需要特化的类型4、函数形参表: 必须要和模板函数的基础参数类型完全相同如果不同编译器可能会报一些奇怪的错误。2.2 类模板的特化类模板特化是指针对某些特殊类型为模板类提供一份专门的实现。当通用模板无法满足某种类型的特殊需求时可以通过特化让该类型使用不同的代码逻辑。类模板特化分为全特化和偏特化全特化是将模板参数完全确定例如template class Aint偏特化是只限定部分模板参数例如templateclass T class AT*。编译器在实例化模板时会优先匹配特化版本如果没有匹配才使用普通模板。2.2.1 全特化全特化即将模板参数列表中所有的参数都确定化所有模版都特化。templateclass T1,class T2 class Data { public: Data() { cout DateT1, T2 endl; } private: T1 _d1; T2 _d2; }; template class Dataint, char { public: Data() { cout Dateint, char endl; } }; int main() { Dataint, int a1; Dataint, char a2; return 0; }2.2.2 偏特化/半特化偏特化也叫半特化即任何针对模版参数进一步进行条件限制设计的特化版本部分模版都特化。templateclass T1,class T2 class Data { public: Data() { cout DateT1, T2 endl; } private: T1 _d1; T2 _d2; }; templateclass T1 class DataT1, double { public: Data() { cout DateT1, double endl; } }; int main() { Dataint, double a3; return 0; }偏特化还可以特化指针和引用templateclass T1,class T2 class DataT1*, T2* { public: Data() { cout DateT1*, T2* endl; } }; templateclass T1, class T2 class DataT1, T2 { public: Data() { cout DateT1, T2 endl; } }; int main() { Dataint*, double* a4; Dataint, double a5; return 0; }2.2.3 类模板特化应用实例在日期类比较的时候我们发现指针比较是一个特例所以我们对函数模板进行了特化同样的在优先级队列中我们需要仿函数完成比较但是传递指针时正常的仿函数无法完成任务我们也可以对类模板进行特化templateclass T class Less { public: bool operator()(const T x1,const T x2)const { return x1 x2; } }; templateclass T class LessT* { public: bool operator()(T* x1, T* x2)const { return *x1 *x2; //要注意如果类型是 int* 那么 T 的值应该是 int 而不是 int* !!!!! } };int main() { lzx::priority_queueDate*,vectorDate*,lzx::LessDate* q1; q1.push(new Date(2018, 5, 10)); q1.push(new Date(2018, 6, 10)); q1.push(new Date(2018, 7, 10)); q1.push(new Date(2018, 8, 10)); while (!q1.empty()) { cout *q1.top() ; q1.pop(); } return 0; }这里特化有两种方向1. 只对Date*类型进行特化。2. 针对指针类型进行特化。三. 模板分离编译3.1 什么是分离编译一个程序(项目)由若干个源文件共同实现而每个源文件单独编译生成目标文件最后将所有目标文件链接起来形成单一的可执行文件的过程称为分离编译模式。3.2 模板的分离编译3.2.1 模板分离代码简单演示Func.h:#define _CRT_SECURE_NO_WARNINGS #pragma once templateclass T T Add(const T left, const T right);Func.cpp:#define _CRT_SECURE_NO_WARNINGS templateclass T T Add(const T left, const T right) { return left right; }Test.cpp:#includeFunc.h int main() { Add(1.2); Add(1.0 2.0); return 0; }3.2.2 分析运行过程3.3 解决方法#define _CRT_SECURE_NO_WARNINGS templateclass T T Add(const T left, const T right) { return left right; } //显式实例化 template int Add(const int left, const int right); template double Add(const double left, const double rght);1、将声明和定义放到一个文件“xxx.hpp里面或者xxx.h其实也是可以的。推荐使用这种。2、模板定义的位置显式实例化。这种方法不实用不推荐使用。四. 模板总结4.1 模板的优点1、模板复用了代码节省资源更快的迭代开发C的标准模板库STL因此而产生2、增强了代码的灵活性。4.2 模板的缺点1、模板会导致代码膨胀问题也会导致编译时间变长2、出现模板编译错误时错误信息非常凌乱不易定位错误。
返回列表