网站建设网上商城心得体会,dede如何生成网站源码,网站网站服务器,wordpress 足球目录 前言 
1.非类型模版参数 
2.模版的特化 
2.1概念 
2.2函数模版特化 
2.3 类模板特化 
2.3.1 全特化和偏特化 
2.3.2类模版特化应用实例 
3.模版分离编译 3.1 什么是分离编译 
3.2 模板的分离编译 
3.3 解决方法 4. 模板总结 
结束语 前言 在模版初阶我们学习了函数模版和类…目录 前言 
1.非类型模版参数 
2.模版的特化 
2.1概念 
2.2函数模版特化 
2.3 类模板特化 
2.3.1 全特化和偏特化 
2.3.2类模版特化应用实例 
3.模版分离编译 3.1 什么是分离编译 
3.2 模板的分离编译 
3.3 解决方法 4. 模板总结 
结束语 前言 在模版初阶我们学习了函数模版和类模版的相关知识对模版有了一定的了解接下来我们将对模版进行进一步的了解话不多说直接上货 本节内容  1.  非类型模板参数    2.  类模板的特化    3.  模板的分离编译  1.非类型模版参数 模板参数分类类型形参与非类型形参 。  类型形参即出现在模板参数列表中跟在class或者typename之类的参数类型名称。  非类型形参就是 用一个常量作为类(函数)模板的一个参数 在类 ( 函数 ) 模板中可将该参数当成常量来使用 。 比如我们简单写一个静态栈可以定义不同大小的栈这里我们没有传默认参数传也可以。 
templatesize_t N
class Stack {
private:int _a[N];int _top;
};
int main() {Stack5s1;Stack10s2;return 0;
} 
其实非类型形参在大小定义方面用的比较多把大小当做常量。对于传参都传的是整数。 注意  1.  浮点数、类对象以及字符串是不允许作为非类型模板参数的 。    2.  非类型的模板参数必须在编译期就能确认结果 。  在C11版本的array用了 非类型的模板参数, 来代替静态数组。 #include array
#include iostream
using namespace std;
int main(){arrayint, 10 a1;arrayint, 100 a2;
int a3[10];
return 0;
} 那么用array定义数组的好处是什么呢是数组初始化吗当然不是。  相比较于int a3[10]其实array的好处是越界检查方面array对于数组的读和写都会进行越界检查而int a3[10],对于读不会检查而写会检查进行的是抽取一般会在数组后面默认分配两个数据大小空间左右。  arrayint, 10 a1;arrayint, 100 a2;
// a1[100]  3;int a3[10];cout  a3[100]  endl;a3[10]  1;
// a3[12]  1; array底层访问是调用了一个函数进行实现都会调用assert语句来判断。 templateclass T, size_t N  10
class array
{
public:T operator[](size_t index) { assert(index  N);return _array[index];}
private:T _array[N];size_t _size;
}; 其实对于数组的定义在C中我们采用vector来定义可以进行初始化。  vectorintv(10,1);  但是如果要频繁的开设数组其实array的效率可能要高些因为array是在栈上开空间的栈是向下生长的vector是在堆上。  
2.模版的特化 
2.1概念 通常情况下 使用模板可以实现一些与类型无关的代码但对于一些特殊类型的可能会得到一些错误的结 果 需要特殊处理比如实现一个专门用来小于比较的函数模版 class Date {
public:Date(int year  1, int month  1, int day  1):_year(year),_month(month),_day(day){}bool operator(const Date other) const {if (_year ! other._year) return _year  other._year;if (_month ! other._month) return _month  other._month;return _day  other._day;}/*friend ostreamoperator(ostream out, const Date d) {out  d._year  -  d._month  -  d._day;return out;}*/
private:int _year;int _month;int _day;
};
template class T
bool Less(const T left,const T right) {return left  right;
}
int main() {cout  Less(1, 2)  endl; // 可以比较结果正确Date d1(2024, 7, 9);Date d2(2024, 7, 8);cout  Less(d1, d2)  endl; // 可以比较结果正确Date* p1  d1;Date* p2  d2;cout  Less(p1, p2)  endl; // 可以比较结果错误return 0;
} 可以看到 Less 绝对多数情况下都可以正常比较但是在特殊场景下就得到错误的结果。上述示例中 p1 指向的d1 显然大于 p2 指向的 d2 对象但是 Less内部并没有比较p1和p2指向的对象内容而比较的是p1和p2 指针的地址这就无法达到预期而错误。  此时就 需要对模板进行特化。即在原模板类的基础上针对特殊类型所进行特殊化的实现方式 。模板特化中分为函数模板特化 与 类模板特化 。 2.2函数模版特化 函数模板的特化步骤  1. 必须要先有一个基础的函数模板  2. 关键字template后面接一对空的尖括号  3. 函数名后跟一对尖括号尖括号中指定需要特化的类型  4. 函数形参表: 必须要和模板函数的基础参数类型完全相同如果不同编译器可能会报一些奇怪的错误。 template class T
bool Less(const T left,const T right) {return left  right;
}template
bool LessDate*(Date* const left, Date* const right)
{return *left  *right;
}
/*
template
bool Lessconst Date*(const Date* const left, const Date* const right)
{return *left  *right;
}
*/ 注意const要放在*之后修饰的才是引用变量本身放在*之前是修饰指向内容 非const特化  template class T
bool Less( T left,T right) {return left  right;
}template
bool LessDate*(Date* left, Date* right)
{return *left  *right;
} 所以对于下面这段代码   Date *  p1    d1 ;     Date *  p2    d2 ;     cout    Less ( p1 ,  p2 )    endl ;  //  调用特化之后的版本而不走模板生成了       注意一般情况下如果函数模板遇到不能处理或者处理有误的类型为了实现简单通常都是将该函数直接给 出。    bool Less(Date* left, Date* right)
{return *left  *right;
}   该种实现简单明了代码的可读性高容易书写因为对于一些参数类型复杂的函数模板特化时特别给出因此函数模板不建议特化。    2.3 类模板特化  2.3.1 全特化和偏特化  全特化即是将模板参数列表中所有的参数都确定化。     偏特化任何针对模版参数进一步进行条件限制设计的特化版本。     templateclass T1, class T2
class Data
{
public:Data() { cout  DataT1, T2  endl; }
private:T1 _d1;T2 _d2;
};
//全特化
template
class Dataint, char
{
public:Data() { cout  Dataint, char  endl; }
private:int _d1;char _d2;
};
//偏特化
templateclass T1
class DataT1, int {
public:Data() { cout  DataT1, int  endl; }
private:T1 _d1;int _d2;
};int main() {Dataint, intd1;Dataint, chard2;Dataint, int d3;return 0;
} 偏特化有以下两种表现方式  部分特化    将模板参数类表中的一部分参数特化。         // 将第二个参数特化为int
template class T1
class DataT1, int
{
public:Data() {coutDataT1, int endl;}
private:T1 _d1;int _d2;
};  参数更进一步的限制    偏特化并不仅仅是指特化部分参数而是针对模板参数更进一步的条件限制所设计出来的一个特化版本    /两个参数偏特化指针类型
//templateclass T1,class T2
templatetypename T1, typename T2
class DataT1*, T2*
{
public:Data()  { cout  DataT1*, T2*  endl;  }
private:T1 _d1;T2 _d2;
};
//两个参数特化引用类型templateclass T1, class T2class DataT1, T2{public:Data()  {  cout  DataT1, T2  endl; }private:T1 _d1;T2 _d2;};//一个指针一个引用templateclass T1, class T2class DataT1, T2*{public:Data() { cout  DataT1, T2*  endl; }private:T1 _d1;T2 _d2;}; 2.3.2类模版特化应用实例 实例1 class Date {
public:Date(int year  1, int month  1, int day  1):_year(year),_month(month),_day(day){}bool operator(const Date d)const{return (_year  d._year) ||(_year  d._year  _month  d._month) ||(_year  d._year  _month  d._month  _day  d._day);}bool operator(const Date d)const{return (_year  d._year) ||(_year  d._year  _month  d._month) ||(_year  d._year  _month  d._month  _day  d._day);}friend ostreamoperator(ostream out, const Date d) {out  d._year  -  d._month  -  d._day;return out;}
private:int _year;int _month;int _day;
};
/*
template class T
bool Less(const T left,const T right) {return left  right;
}
*/
templateclass T
struct Less
{bool operator()(const T x, const T y) const{return x  y;}
};
int main() {vectorDated1;d1.push_back(Date(2024, 8, 25));d1.push_back(Date(2024, 8, 24));d1.push_back(Date(2024, 8, 27));sort(d1.begin(), d1.end(), LessDate());for (const auto date : d1) {cout  date  endl;}return 0;
}     实例2 
#include iostream
#include vector
#include algorithm
using namespace std;
class Date {
public:Date(int year  1, int month  1, int day  1):_year(year),_month(month),_day(day){}bool operator(const Date d)const{return (_year  d._year) ||(_year  d._year  _month  d._month) ||(_year  d._year  _month  d._month  _day  d._day);}bool operator(const Date d)const{return (_year  d._year) ||(_year  d._year  _month  d._month) ||(_year  d._year  _month  d._month  _day  d._day);}friend ostreamoperator(ostream out, const Date d) {out  d._year  -  d._month  -  d._day;return out;}private:int _year;int _month;int _day;
};
templateclass T
class Less
{
public:bool operator()(const T x, const T y) const{return x  y;}
};
// 对Less类模板按照指针方式特化/*
template class T
bool Less(const T left,const T right) {return left  right;
}
*/int main()
{Date d1(2022, 7, 7);Date d2(2022, 7, 6);Date d3(2022, 7, 8);vectorDate v1;v1.push_back(d1);v1.push_back(d2);v1.push_back(d3);// 可以直接排序结果是日期升序sort(v1.begin(), v1.end(), LessDate());for (const auto date : v1) {cout  date  endl;}vectorDate* v2;v2.push_back(d1);v2.push_back(d2);v2.push_back(d3);// 可以直接排序结果错误日期还不是升序而v2中放的地址是升序// 此处需要在排序过程中让sort比较v2中存放地址指向的日期对象// 但是走Less模板sort在排序时实际比较的是v2中指针的地址因此无法达到预期sort(v2.begin(), v2.end(), LessDate*());for (const auto date : v2) {cout  *date  endl;}return 0;
} 通过观察上述程序的结果发现对于日期对象可以直接排序并且结果是正确的。但是如果待排序元素是指针结果就不一定正确。因为sort 最终按照 Less 模板中方式比较所以只会比较指针而不是比较指针指向空间中内容此时可以使用类版本特化来处理上述问题 // 对Less类模板按照指针方式特化
template
struct LessDate*
{bool operator()(Date* x, Date* y) const{return *x  *y;}
};  3.模版分离编译 3.1 什么是分离编译  一个程序项目由若干个源文件共同实现而每个源文件单独编译生成目标文件最后将所有目标文件链接起来形成单一的可执行文件的过程称为分离编译模式。  3.2 模板的分离编译  假如有以下场景模板的声明与定义分离开在头文件中进行声明源文件中完成定义。 // a.h
templateclass T
T Add(const T left, const T right);
// a.cpp
templateclass T
T Add(const T left, const T right)
{return left  right;
}
// main.cpp
#includea.h
int main()
{Add(1, 2);Add(1.0, 2.0);return 0;
} C/C程序的运行过程通常包括以下几个步骤1. 预处理Preprocessing    - 预处理器处理源代码文件中的预处理指令如 #include、#define、#if、#ifdef 等。    - 预处理器将包含的文件内容插入到源文件中处理宏定义条件编译指令等。    - 结果是一个扩展的源代码文件通常以 .i 文件C语言或 .ii 文件C语言表示。2. 编译Compilation    - 编译器将预处理后的源代码翻译成汇编语言。    - 在这个阶段编译器进行词法分析、语法分析、语义分析、中间代码生成和优化等操作。    - 生成的汇编语言文件通常以 .s 文件表示。3. 汇编Assembly    - 汇编器将汇编语言转换成机器语言指令这些指令是二进制形式的可以被计算机的CPU直接执行。    - 生成的目标代码文件通常以 .oLinux/Unix系统或 .objWindows系统表示。4. 链接Linking    - 链接器将一个或多个目标文件以及所需的库文件合并成一个可执行文件。    - 在这个阶段链接器解析外部引用和符号合并相同的函数和数据进行重定位等操作。    - 最终生成的可执行文件通常以 .exeWindows系统或无扩展名Linux/Unix系统表示。 5. 加载Loading    - 当程序运行时操作系统负责将可执行文件加载到内存中。    - 加载器读取可执行文件并将程序代码和数据映射到内存的适当位置。 6. 执行Execution    - CPU开始执行程序的主函数程序正式开始运行。    - 在执行过程中程序可能会进行各种计算、输入输出操作、调用库函数等。 7. 终止Termination    - 程序执行完成后或者遇到无法处理的错误时程序会终止。    - 在终止前程序可能需要执行一些清理工作如关闭打开的文件、释放分配的内存等。     链接之前各文件没有交互模版没有实例化没有生成指令代码链接就出现问题。 3.3 解决方法     1.  将声明和定义放到一个文件  xxx.hpp  里面或者 xxx.h 其实也是可以的 。 推荐  用的地方就直接有定义了。     2.  模板定义的位置显式实例化 。这种方法不实用不推荐。   显示实例化  template int Add(const intleft,const intright) 对于其他类型照样所以比较复杂   4. 模板总结   【优点】    1.  模板复用了代码节省资源更快的迭代开发 C 的标准模板库 (STL) 因此而产生    2.  增强了代码的灵活性    【缺陷】    1.  模板会导致代码膨胀问题也会导致编译时间变长    2.  出现模板编译错误时错误信息非常凌乱不易定位错误  结束语 本篇就到此结束啦内容有点多相信大家通过本篇博客对模版的认识有了进一步的理解。 最后感谢各位友友的支持支持小编的留个赞吧