【C++】---模板进阶

【C++】---模板进阶

  • 一、模版参数
    • 1、类型参数
    • 2、非类型参数
  • 二、模板的特化
    • 1、函数模板的特化
    • 2、类模板特化
      • (1)全特化
      • (2)偏特化
  • 三、模板分离编译
    • 1、模板支持分离编译吗?
    • 2、为什么模板不支持分离编译?
    • 3、如何编译模板文件?
  • 四、总结

一、模版参数

模板参数分为:类型参数 和 非类型参数

1、类型参数

类型参数,出现在:模板的参数列表。跟在class或者typename之后的参数类型的名称。

比如下面的,模板类型参数:T

template<class T>
void swap(T& x, T& y)
{T tmp = x;x = y;y = tmp;
}

2、非类型参数

(1)用一个常量作为一个类或者函数模板的一个参数,在类或者函数模板中把这个参数当作常量来使用。比如下面代码中的N就是:非类型的模板参数

// 非类型模板参数
template<class T ,size_t N>
class Car
{
private:T _arr[N];
};int main()
{Car<int, 20> c1;// N=20Car<int, 40> c2;// N=40return 0;
}

(2)对于函数模板也可以给缺省值,给缺省值的规则跟之前讲的类和对象的规则一样。只能从后往前给,按顺序不能跳着给。


// 非类型模板参数
template<class T=int ,size_t N=30>
class Car
{
private:T _arr[N];
};int main()
{Car<int, 20> c1;// N=20Car<int, 40> c2;// N=40Car<> c3;// 这里没有实例化模板,使用了模板默认的缺省值!return 0;
}

注意:

1、目前来看非类型模板参数只支持整型,不支持浮点型和字符型:

template<class T,double N>

在这里插入图片描述
2、非类型模板参数必须在编译时期就能确认编译结果。

// 非类型模板参数
template<class T , size_t N>//template<class T,double N>
class Car
{
private:T _arr[N];
};int main()
{Car<int> c1;// N(非类型模板参数)必须在编译时期就确认好结果!return 0;
}

在这里插入图片描述

二、模板的特化

什么叫:模板的特化?

通常情况下,使用模板可以实现一些与类型无关的代码,但对于一些特殊类型的可能会得到一些错误的结果,需要特殊处理,比如:实现了一个专门用来进行小于比较的函数模板

template<class T>// 函数模板
bool Less(T left, T right)
{return left < right;
}int main()
{cout << Less(1, 3) << endl;// 比较结果正确Date d1(2024, 4, 1);Date d2(2024, 5, 1);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指针的地址,这就无法达到预期而错误。

此时我们就要对模板进行特化,模板的特化就是:在原有模板的基础上,对特殊类型进行特殊处理。
模板的特化分为:函数模板特化 和 类模板特化。

1、函数模板的特化

函数模板的特化步骤:

  1. 必须要先有一个基础的函数模板
  2. 关键字template后面接一对空的尖括号<>
  3. 函数名后跟一对尖括号,尖括号中指定需要特化的类型
  4. 函数形参表: 必须要和模板函数的基础参数类型完全相同,如果不同编译器可能会报一些奇怪的错误。
// 函数模板 -- 参数匹配
template<class T>
bool Less(T left, T right)
{return left < right;
}// 对Less函数模板进行特化
template<>
bool Less<Date*>(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;
}

注意:一般情况下如果函数模板遇到不能处理或者处理有误的类型,为了实现简单通常都是将该函数直接给出。

bool Less(Date* left, Date* right)
{return *left < *right;
}

2、类模板特化

类模板在没有特化之前,调用的都是原模板,如下代码:

#include<iostream>
using namespace std;//类模板
template<class T1, class T2>
class Data
{
public:Data(){cout << "Data<T1,T2>" << endl;}
};void Test_Class()
{Data<int, int> d1;Data<int, char> d2;
}int main()
{return 0;
}

类模板分为全特化和偏特化,但是类模板只有一种写法,没有简写形式

(1)全特化

全特化是把模板参数列表中的所有参数都确定化。

比如想把T1指定成int,T2指定成char

template<class T1, class T2>
class Date
{
private:T1 _d1;T2 _d2;
public:Date(){cout << "Date<T1,T2>" << endl;}};// 全特化:将类模板,里面的所有参数列表,都确定化!
template<>
class Date<int,char>
{
private:int _d1;char _d2;
public:Date(){cout << "Date<int,char>" << endl;}
};void Test_Date()
{Date<int, int> d1;// 创建d1的时候,走的是第1个类模板!Date<int, char> d2;// 创建d2的时候,走的是第2个类模板!(因为特化后的模板类型就是:int,char,正好跟d2对接!有现成的就吃现成的!)
}int main()
{Test_Date();return 0;
}

(1)创建d1的时候,走的是第1个类模板!
(2)创建d2的时候,走的是第2个类模板!(因为特化后的模板类型就是:int,char,正好跟d2对接!有现成的就吃现成的!)
在这里插入图片描述

(2)偏特化

偏特化是任何针对模板参数进一步进行条件限制的特化版本。偏特化分为两种表现方式:

①部分特化:把模板参数类表中的一部分参数特化

// 偏特化:部分特化
template<class T1>
class Date<T1, double>
{
private:T1 _d1;double _d2;
public:Date(){cout << "Date<T1,double>" << endl;}
};void Test_Date()
{Date<int, int> d1;// 创建d1的时候,走的是第1个类模板!Date<int, double> d2;// 创建d2的时候,走的是第2个类模板!
}int main()
{Test_Date();return 0;
}

在这里插入图片描述
②对参数进一步限制:对模板参数做更进一步的条件限制

可以将参数偏特化为指针类型 :

//偏特化-两个参数偏特化为指针类型,只指定指针,什么类型的指针都可以
template<typename T1,typename T2>
class Data<T1*, T2*>
{
public:Data(){cout << "Data<T1*,T2*>" << endl;}
private:T1 _d1;T2 _d2;
};
void Test_Class()
{Data<int, int> d1;Data<int, double> d2;Data<int, char> d3;Data<char*, char*> d4;//会调用两个参数偏特化为指针类型的偏特化
}

也可以将参数偏特化为引用类型:

//偏特化-两个参数偏特化为引用类型,只指定引用,什么类型的引用都可以
template<typename T1, typename T2>
class Data<T1&, T2&>
{
public:Data(const T1& d1,const T2& d2):_d1(d1),_d2(d2){cout << "Data<T1&,T2&>" << endl;}
private:const T1& _d1;const T2& _d2;
};
void Test_Class()
{Data<int, int> d1;Data<int, double> d2;Data<int, char> d3;Data<char*, char*> d4;//会调用两个参数偏特化为指针类型的偏特化Data<double&, double&> d5(2.1, 3.2);//会调用两个参数偏特化为引用类型的偏特化
}

三、模板分离编译

什么是分离编译?

一个程序(项目)由若干个源文件共同实现,而每个源文件单独编译生成目标文件,最后将所有目标文件链接起来形成单一的可执行文件的过程称为分离编译模式。

1、模板支持分离编译吗?

对于分离式编译的模板:
template.h:

template<class T>
T Add(const T& left, const T& right);

template.cpp :

#include "template.h"template<class T>
T Add(const T& left, const T& right)
{return left + right;
}

template-main.cpp:

#include "template.h"int main()
{Add(1, 2);Add(1.0, 2.0);return 0;
}

上述代码运会报错!

2、为什么模板不支持分离编译?

在这里插入图片描述

3、如何编译模板文件?

(1)显示指定实例化

(2)推荐:将声明和定义放在同一个文件

解决方法:

  1. 将声明和定义放到一个文件 “xxx.hpp” 里面或者xxx.h其实也是可以的。推荐使用这种。
  2. 模板定义的位置显式实例化。这种方法不实用,不推荐使用。

四、总结

【优点】
1. 模板复用了代码,节省资源,更快的迭代开发,C++的标准模板库(STL)因此而产生
2. 增强了代码的灵活性

【缺陷】
1. 模板会导致代码膨胀问题,也会导致编译时间变长
3. 出现模板编译错误时,错误信息非常凌乱,不易定位错误


好了,今天的分享就到这里了
如果对你有帮助,记得点赞👍+关注哦!
我的主页还有其他文章,欢迎学习指点。关注我,让我们一起学习,一起成长吧!

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/5667.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

google search API 获取

登录谷歌云启动服务 首先登录谷歌云Google Cloud: https://console.cloud.google.com/&#xff0c;登录后创建一个项目。 选择创建的项目&#xff0c;进入API库。搜索Google Search。 选择custom Search API并启用。 此外&#xff0c;有个非常具有类似的API-- Google Search …

3D建模在游戏行业的演变和影响

多年来&#xff0c;游戏行业经历了显着的转变&#xff0c;这主要是由技术进步推动的。 深刻影响现代游戏的关键创新之一是 3D 建模领域。 从像素化精灵时代到我们今天探索的错综复杂的游戏世界&#xff0c;3D 建模已成为游戏开发不可或缺的基石。 本文讨论 3D 建模在游戏行业中…

PyVista 3D数据可视化 Python 库 一行代码实现裁剪 含源码

简介&#xff1a; Pyvista是一个用于科学可视化和分析的Python库,使3D数据可视化变得更加简单和易用&#xff1b; 只增加一行代码就可以实现裁剪&#xff1b; 1.效果&#xff1a; 2.代码如下&#xff1a; 加载模型数据&#xff1a; 代码实现&#xff1a; import pyvista a…

查找算法之二分查找

一、算法介绍 二分查找&#xff0c;也称为折半查找&#xff0c;是一种在有序数组中查找特定元素的高效算法。对于包含 n 个元素的有序数组&#xff0c;二分查找的步骤如下&#xff1a; 确定搜索范围&#xff1a;首先&#xff0c;将要查找的元素与数组中间的元素进行比较。如果…

引领农业新质生产力,鸿道(Intewell®)操作系统助力农业机器人创新发展

4月27日至29日&#xff0c;2024耒耜国际会议在江苏大学召开。科东软件作为特邀嘉宾出席此次盛会&#xff0c;并为江苏大学-科东软件“农业机器人操作系统”联合实验室揭牌。 校企联合实验室揭牌 在开幕式上&#xff0c;江苏大学、科东软件、上交碳中和动力研究院、遨博智能研究…

查看笔记本电池容量/健康状态

1. 打开命令行提示符 快捷键“win R”后输入“cmd” 2. 在命令提示符中输入命令 “powercfg /batteryreport" 并回车 3. 查看文件 最后就可以看到笔记本的电池使用报告了

高效率的做事方法?

高效率的做事方法可以帮助我们更好地管理时间和资源&#xff0c;以下是一些建议&#xff1a; 1.明确目标和计划&#xff1a; 在开始任何任务之前&#xff0c;先明确你的目标是什么。 制定一个详细的计划&#xff0c;包括步骤、时间表和预期结果。 将任务分解成小块&#xff0…

第11章 数据库技术(第一部分)

一、数据库技术术语 &#xff08;一&#xff09;术语 1、数据 数据描述事物的符号描述一个对象所用的标识&#xff0c;可以文字、图形、图像、语言等等 2、信息 现实世界对事物状态变化的反馈。可感知、可存储、可加工、可再生。数据是信息的表现形式和载体&#xff0c;信…

python实现的基于单向循环链表插入排序

相比于定义一个循环双向链表来实现插入排序来说&#xff0c;下面的实现采用一个单向循环链表来实现&#xff0c;并且不需要定义一个单向循环链表类&#xff0c;而是把一个list&#xff08;数组/顺序表&#xff09;当成单向循环链表来用&#xff0c;list的元素是一个包含两个元素…

【Windows,亲测有效】手动激活Sublime Text

前言 Sublime Text 是一款非常好用的文本编辑器&#xff0c;但是免费版时不时会跳弹窗 本方法无毒无害&#xff0c;简单易上手 2023/12/22 更新&#xff1a;实测从 4143 支持到 4169 开始 先确保你用的是官方版本的 Sublime Text&#xff0c;还没下的可以去官方下载&#…

net lambda 、 匿名函数 以及集合(实现IEnumerable的 如数组 、list等)

匿名函数&#xff1a;》》》 Action a1 delegate(int i) { Console.WriteLine(i); }; Lambda:>>> Aciont a1 (int i) > { Console.WriteLine(i); }; 可以简写 &#xff08;编译器会自动根据委托类型 推断&#xff09; Action a1 &#xff08;i&#xff09;> {…

笔记本无线网络共享给有线使用

1.鼠标右击wifi图标选择打开网络和Internet设置 2.选择WLAN项&#xff0c;点击进入更改适配器选项 3.进入到以下界面&#xff0c;右击以太网选择启动&#xff08;不确定的话可以在设备管理器查看网卡&#xff09; 4.右击WLAN选项&#xff0c;点击属性 5.点击共享&#xff0…

esp32s3使用psram后音频播报不了的问题解决记录

idf.py menuconfig开启psram后会报错 提示需要打补丁&#xff1a; 根据提示切换到IDF_PATH目录&#xff0c;然后执行git apply %ADF_PATH%/ida_patches/idf5.0_freertos.patch打补丁。 再次编译提示如下错误&#xff1a; assert failed: spi_flash_disable_interrupts_cach…

【Qt QML】Pane组件

Pane&#xff08;窗格&#xff09;提供与应用程序样式和主题匹配的背景色。窗格不提供自己的布局&#xff0c;但需要您定位其内容&#xff0c;例如通过创建RowLayout或ColumnLayout。 声明为窗格的子项的项自动成为窗格的contentItem的父项。动态创建的项需要显式地添加到conte…

VSCode 配置 CMake

VSCode 配置 C/C 环境的详细过程可参考&#xff1a;VSCode 配置 C/C 环境 1 配置C/C编译环境 方案一 如果是在Windows&#xff0c;需要安装 MingW&#xff0c;可以去官网(https://sourceforge.net/projects/mingw-w64/)下载安装包。 注意安装路径不要出现中文。 打开 windows…

06 - 步骤 add constants

简介 Add Constants 步骤是用于在数据流中添加常量字段的步骤。它允许用户在数据流中插入一个或多个常量字段&#xff0c;并为这些字段指定固定的数值、字符串或其他类型的常量值。 使用 场景 我需要在数据清后&#xff0c;这个JSON 字符串有一个固定的行流数据。 1、拖拽…

数字旅游引领未来智慧之旅:科技应用深度重塑旅游生态,智慧服务全面升级打造极致高品质旅游体验

随着信息技术的飞速发展&#xff0c;数字旅游作为旅游业与科技融合的新兴业态&#xff0c;正以其独特的魅力和优势&#xff0c;引领着旅游业迈向智慧之旅的新时代。数字旅游不仅通过科技应用重塑了旅游生态&#xff0c;更通过智慧服务为游客带来了高品质的旅游体验。本文将深入…

Flask简介

Flask简介 安装概述使用PyCharm创建一个Flask程序 Flask程序的基本结构初始化路由和视图函数启动服务器请求-响应循环 安装 概述 Flask算是小型框架&#xff0c;小到可以称为“微框架”。Flask 非常小&#xff0c;因此你一旦能够熟练使用它&#xff0c;很可能就能读懂它所有的…

《MySQL对库的基本操作》

文章目录 一、查看数据库列表查看数据库中的所有表想知道当前处于哪个数据库里 二、创建一个数据库三、删除一个数据库知道两个集1.字符集2.校验集修改数据库的字符集和编码集 不同的校验码对数据库的影响四、数据库的备份与恢复注意事项&#xff1a;备份数据库中的表 总结 一、…

现代神经网络总结(AlexNet VGG GoogleNet ResNet的区别与改进)

VGG NIN GoogleNet 1.VGG&#xff0c;NIN&#xff0c;GoogleNet的块结构图对比(注意:无AlexNet) 这些块带来的区别与细节 AlexNet未使用块,主要对各个层进行了解: 卷积:捕捉特征 relu:增强非线性 池化层:减少计算量 norm:规范数据分布 全连接层:分类VGG块的改善(对比AlexNe…