0


【初阶与进阶C++详解】第十二篇:模板进阶(函数模板特化+类模板特化+模板分离编译)

🏆个人主页:企鹅不叫的博客

​ 🌈专栏

  • C语言初阶和进阶
  • C项目
  • Leetcode刷题
  • 初阶数据结构与算法
  • C++初阶和进阶
  • 《深入理解计算机操作系统》
  • 《高质量C/C++编程》
  • Linux

⭐️ 博主码云gitee链接:代码仓库地址

⚡若有帮助可以【关注+点赞+收藏】,大家一起进步!

💙系列文章💙

【初阶与进阶C++详解】第一篇:C++入门知识必备

【初阶与进阶C++详解】第二篇:C&&C++互相调用(创建静态库)并保护加密源文件

【初阶与进阶C++详解】第三篇:类和对象上(类和this指针)

【初阶与进阶C++详解】第四篇:类和对象中(类的六个默认成员函数)

【初阶与进阶C++详解】第五篇:类和对象下(构造+static+友元+内部类

【初阶与进阶C++详解】第六篇:C&C++内存管理(动态内存分布+内存管理+new&delete)

【初阶与进阶C++详解】第七篇:模板初阶(泛型编程+函数模板+类模板+模板特化+模板分离编译)

【初阶与进阶C++详解】第八篇:string类(标准库string类+string类模拟实现)

【初阶与进阶C++详解】第九篇:vector

【初阶与进阶C++详解】第十篇:list

【初阶与进阶C++详解】第十一篇:stack+queue+priority_queue+deque


文章目录


💎一、非类型模板参数

模板参数分类类型形参非类型形参

  • 类型模板形参:出现在模板参数列表中,跟在class或者typename后面的参数类型名称。
  • 非类型模板形参:用一个常量(浮点数,字符串,类对象不允许作为非类型模板参数)(可以是 int short char long longlong)作为模板的一个参数,必须是整形家族中的类型参数。
  • template<classT=int, size_t N =10>classarray{private: T _array[N]; size_t _size;}

💎二、模板的特化

模板特化:在原模板类的基础上,针对特殊类型所进行的特殊化的实现。分为函数模板特化类模板特化

🏆1.函数模板的特化

  1. 必须先有一个基础的函数模板
  2. 关键字template后面接一对空的尖括号<>
  3. 函数名后跟一对尖括号<>,里面指定需要的特化的类型
  4. 函数形参列表:必须和函数模板的基础参数类型完全一致// 模板template<classT>boolIsEqual(T& left, T& right){return left == right;}// 特化template<>boolIsEqual<constchar*const>(constchar*const& left,constchar*const& right){returnstrcmp(left, right)==0;}

🏆2.类模板的特化

2.1全特化

对类模板参数列表的类型全部都确定

template<classT1,classT2>classDate{public:Date(){
        cout <<"Date<T1, T2>"<< endl;}private:
    T1 _d1;
    T2 _d2;};// 全特化template<>classDate<int,double>{public:Date(){
        cout <<"Date<int, double>"<< endl;}private:int _d1;double _d2;};

2.2偏特化

偏特化:任何针对模版参数进一步进行条件限制设计的特化版本

偏特化有两种表现方式,一种是部分参数特化,一种是参数修饰特化

部分特化,模板参数类表中一部分参数特化

//第二个参数特化template<classT1>classtest<T1,double>{public:test(){
        cout <<"test<T1, double>"<< endl;}private:
    T1 _x;double _y;};intmain(){
    test<double,double> t1;
    test<int,double> t2;}

参数更进一步限制,偏特化不指是指特化部分参数,而是针对模板参数更进一步的条件限制所设计出来的一个特化版本

//如下有T1*和T2*,是模板的类型转为指针类型和引用类型/template<classT1,classT2>classtest<T1*, T2*>{public:test(){
        cout <<"test<T1*, T2*>"<< endl;}private:
    T1* _x;
    T2* _y;};intmain(){
    test<int*,double*> t;}

💎三、模板分离编译

🏆1.实例

分离编译:C++的编译器却不支持模板的分离编译,一旦进行分离编译,就会出现链接错误,下面代码就会报错。详情看这里传送门

// a.h#pragmaonce// 普通函数voidSwap(int& a,int& b);// 函数模板template<classT>
T Add(const T& a,const T& b);// a.cpp#define_CRT_SECURE_NO_WARNINGS1#include"a.h"// 普通函数voidSwap(int& a,int& b){int tmp = a;
    a = b;
    b = tmp;}// 函数模板template<classT>
T Add(const T& a,const T& b){return a + b;}// test.cpp#include"a.h"intmain(){int a =3;int b =4;Swap(a, b);
    cout <<"a = "<< a <<" b = "<< b << endl;
    cout <<Add(a, b)<< endl;return0;}

🏆2.原因

1.模板在.cpp中定义了,由于不知道T的类型,所以没有对模板进行实例化。
2.a.h 和 a.cpp 都没有对模板进行实例化,因为不知道T的类型。
3.因为没有对模板进行实例化,所以没有函数参数,也就没有函数地址,所以在链接时,test.cpp中的调用Add函数时,没有函数地址,call调用不到Add函数,所以报错。

🏆3.解决方法

  1. 暴力:将声明和定义统一放在一个.h或.hpp的文件中
  2. 模板定义位置显示实例化(不推荐,这样就失去了泛型的特点)

💎四、模板优缺点

【优点】

​ 1.模板复用了代码,节省资源,更快的迭代开发

​ 2.增强了代码的灵活性

【缺点】

​ 1.导致编译时间变长

​ 2.出现模板编译错误时,错误信息非常凌乱,不易定位错误


标签: c++ java 算法

本文转载自: https://blog.csdn.net/YQ20210216/article/details/126892284
版权归原作者 企鹅不叫 所有, 如有侵权,请联系我们删除。

“【初阶与进阶C++详解】第十二篇:模板进阶(函数模板特化+类模板特化+模板分离编译)”的评论:

还没有评论