网站互联大丰专业做网站

当前位置: 首页 > news >正文

网站互联,大丰专业做网站,网上商城该怎么推广,官方网站建设流程及费用模板进阶 一、非类型模板参数二、模板的特化1. 函数模板的特化2. 类模板特化3. 模板特化的应用 三、模板的分离编译1. 分离编译2. 模板的分离编译3. 解决方法 四、模板总结 我们在 初识模板 中已经初步接触过模板了#xff0c;下面我们开始更进一步学习模板。 一、非类型模板… 模板进阶 一、非类型模板参数二、模板的特化1. 函数模板的特化2. 类模板特化3. 模板特化的应用 三、模板的分离编译1. 分离编译2. 模板的分离编译3. 解决方法 四、模板总结 我们在 初识模板 中已经初步接触过模板了下面我们开始更进一步学习模板。 一、非类型模板参数 模板参数分类类型形参与非类型形参。 类型形参出现在模板参数列表中跟在 class 或者 typename 之类的参数类型名称。非类型形参就是用一个常量作为类(函数)模板的一个参数在类(函数)模板中可将该参数当成常量来使用而且非类型模板参数只支持整型。 例如我们定义一个 Stack 类我们在实例化的时候传入需要用的空间大小这样就可以避免扩容或者空间浪费的问题了如下 template class T, size_t Nclass Stack{public:Stack() {}private:T _a[N];};int main(){Stackint, 100 st1;Stackdouble, 1000 st2;return 0;}注意 浮点数、类对象以及字符串是不允许作为非类型模板参数的只支持整型。非类型的模板参数必须在编译期就能确认结果。 二、模板的特化

  1. 函数模板的特化 函数模板的特化步骤 必须要先有一个基础的函数模板关键字 template 后面接一对空的尖括号函数名后跟一对尖括号尖括号中指定需要特化的类型函数形参表: 必须要和模板函数的基础参数类型完全相同如果不同编译器可能会报一些奇怪的错误 例如我们要对日期类的指针进行比较如果直接走模板生成的函数就会按照指针的大小进行比较但这并不是我们想要的所以我们可以对函数模板进行特化如下 // 函数模板特化// 函数模板 – 参数匹配templateclass Tbool Less(T left, T right){return left right;}// 对Less函数模板进行特化templatebool LessDate(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;}2. 类模板特化 假设有一个日期类它的原模板如下 templateclass T1, class T2class Data{public:Data() { cout DataT1, T2 endl; }private:T1 _d1;T2 _d2;};全特化 全特化即是将模板参数列表中所有的参数都确定化如日期类的全特化 // 全特化templateclass Dateint, char{public:Date() { cout Dateint, char endl; }};我们实例化两个对象分别调用原模板和全特化模板 偏特化 偏特化任何针对模版参数进一步进行条件限制设计的特化版本。比如对于上面的日期类原模板。 偏特化有以下两种表现方式 1部分特化将模板参数类表中的一部分参数特化。 例如 // 偏特化1.// 将第二个参数特化为inttemplate class T1class DateT1, int{public:Date() { cout DateT1, int endl; }};2参数更进一步的限制 偏特化并不仅仅是指特化部分参数而是针对模板参数更进一步的条件限制所设计出来的一个特化版本。 例如 // 偏特化2.// 两个参数偏特化为指针类型template class T1, class T2class Date T1, T2{public:Date() { cout DateT1, T2 endl; }};我们分别针对两种偏特化的模板实例化对象如下 我们可以看到编译器确实调用了特化的 int 版本和特化的指针版本。 如果有多个模板符合实例化的对象编译器会选择最优的那一个进行实例化。
  2. 模板特化的应用 假如有如下专门用来按照小于比较的类模板 Less templateclass Tstruct Less{bool operator()(const T x, const T y) const{return x y;}};我们实例化出几个对象并将它们放入 vectorDate 中进行排序 int main(){Date d1(2023, 10, 7);Date d2(2023, 10, 6);Date d3(2023, 10, 8);vectorDate v1;v1.push_back(d1);v1.push_back(d2);v1.push_back(d3);// 可以直接排序结果是日期升序sort(v1.begin(), v1.end(), LessDate());return 0;}我们以上的方法是可以直接排序的但是现在我们要将 d1、d2、d3 的地址放入 vectorDate* 中呢例如 int main(){Date d1(2023, 10, 7);Date d2(2023, 10, 6);Date d3(2023, 10, 8);vectorDate* v2;v2.push_back(d1);v2.push_back(d2);v2.push_back(d3);// 不能直接排序结果是错误的sort(v2.begin(), v2.end(), LessDate());return 0;}如果我们还是以上面的小于比较的类模板进行排序结果是错误的因为按照上面的比较方法比较的是地址而地址的大小每次传入是不一样的所以每一次比较的大小都是不一样的所以我们可以对 Less 类模板按照指针的方式特化如下 // 对Less类模板按照指针方式特化templatestruct LessDate{bool operator()(Date* x, Date* y) const{return *x *y;}};特化之后在运行上述代码就可以得到正确的结果。 三、模板的分离编译
  3. 分离编译 一个程序项目由若干个源文件共同实现而每个源文件单独编译生成目标文件最后将所有目标文件链接起来形成单一的可执行文件的过程称为分离编译模式。
  4. 模板的分离编译 假如有以下场景模板的声明与定义分离开在头文件中进行声明源文件中完成定义 // a.htemplateclass TT Add(const T left, const T right);// a.cpptemplateclass TT Add(const T left, const T right){return left right;}// main.cpp#includea.hint main(){Add(1, 2);Add(1.0, 2.0);return 0;}C/C 程序要正常运行一般要经过以下步骤预处理 – 编译 – 汇编 – 链接。 在 a.cpp 中编译器没有看到对 Add 模板函数的实例化因此不会生成具体的加法函数。 在链接阶段编译器会将多个obj文件合并成一个并处理没有解决的地址问题而在 main.obj 中调用的 Add int 和 Add double 编译器在链接时才会找其地址但是这两个函数没有实例化没有生成具体代码因此链接时报错。
  5. 解决方法 将声明和定义放到一个文件 “xxx.hpp” 里面或者 “xxx.h” 其实也是可以的推荐使用这种。模板定义的位置显式实例化。这种方法不实用不推荐使用。 四、模板总结 【优点】 模板复用了代码节省资源更快的迭代开发C的标准模板库(STL)因此而产生增强了代码的灵活性 【缺陷】 模板会导致代码膨胀问题也会导致编译时间变长出现模板编译错误时错误信息非常凌乱不易定位错误