【C++】模板进阶

👀樊梓慕:个人主页

 🎥个人专栏:《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C++》《Linux》《算法》

🌝每一个不曾起舞的日子,都是对生命的辜负


目录

前言

1.非类型模板参数

2.模板的特化

2.1函数模板特化

2.2类模板特化 

2.2.1全特化

2.2.2偏特化

3.模板的分离编译

4.模板总结


前言

本篇文章博主会与大家共同学习非类型模板参数、类模板的特化以及模板的分离编译相关内容。


欢迎大家📂收藏📂以便未来做题时可以快速找到思路,巧妙的方法可以事半功倍。

=========================================================================

GITEE相关代码:🌟fanfei_c的仓库🌟

=========================================================================


1.非类型模板参数

我们之前学习的模板,知道模板参数一般都是『 类型』。

可是还存在有一种模板参数是非类型的,这种参数被称为非类型模板参数,一般为常量,或者说是『 整型常量』。

  • 类型形参: 出现在模板参数列表中,跟在class或typename关键字之后的参数类型名称。
  • 非类型形参: 用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用。

比如:

template<class T, size_t N> //N:非类型模板参数
class StaticArray
{
public:size_t arraysize(){return N;}
private:T _array[N]; //利用非类型模板参数指定静态数组的大小
};

非类型模板参数基本上是用来定义数组或某种个数值。 

注意:

  1. 非类型模板参数只允许使用整型家族,浮点数、类对象以及字符串是不允许作为非类型模板参数的。
  2. 非类型的模板参数在编译期就需要确认结果,因为编译器在编译阶段就需要根据传入的非类型模板参数生成对应的类或函数。

2.模板的特化

特化可以理解为『 特殊处理』,即当模板参数为某一种指定类型时, 不走默认的模板,而走我们为该类型单独设计的模板。

比如:

下面是用于比较两个任意相同类型的数据是否相等的函数模板。

template<class T>
bool Equals(T x, T y)
{return x == y;
}

在以下场景,可以正确的使用;

cout << Equals(1, 1) << endl;
cout << Equals(1.1, 2.2) << endl;

但当遇到下面这种情况时,结果往往不是我们所预期的:

char a1[] = "hello cpp";
char a2[] = "hello cpp";
cout << Equals(a1, a2) << endl;

假设我们设计该函数模板时的目的就是判断两个内容是否相等,遇到普通的比如整型、浮点型等数据当然可以正确比较,但当遇到字符串这种,我们想的是判断他们的内容是否相等,但是在实际传递时我们传递的是字符串的地址『 指针』,这也就导致比较的是地址是否相等,这就与我们的初衷所违背。

所以我们需要对指针这种类型作特殊处理,单独设计一个新的函数模板,这就是所谓的『 特化』。

特化:在原模板类的基础上,针对特殊类型所进行的特殊化的实现方式。


2.1函数模板特化

函数模板的特化步骤:

  1. 首先必须要有一个基础的函数模板
  2. 关键字template后面接一对的尖括号<>。
  3. 『 函数名后跟一对尖括号』,尖括号中指定需要特化的类型
  4. 函数形参表必须要和模板函数的基础参数类型完全相同,否则不同的编译器可能会报一些奇怪的错误。

根据以上步骤,我们可以针对上面的模板特化:

//基础的函数模板
template<class T>
bool Equals(T x, T y)
{return x == y;
}
//对于char*类型的特化
template<>
bool Equals<char*>(char* x, char* y)
{return strcmp(x, y) == 0;
}

 当然如果你觉得麻烦,可以不采用特化的方式。

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

bool Equals(char* x, char* y)
{return strcmp(x, y) == 0;
}

该种实现简单明了,代码的可读性高,容易书写,因为对于一些参数类型复杂的函数模板,特化是特别给出,因此『 函数模板不建议特化』。 


2.2类模板特化 

类模板特化非为:全特化、偏特化两种。

类模板的特化步骤:

  1. 首先必须要有一个基础的类模板。
  2. 关键字template后面接一对空的尖括号<>。
  3. 类名后跟一对尖括号,尖括号中指定需要特化的类型。

2.2.1全特化

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

例如:

template<class T1, class T2>
class Fan
{
public://构造函数Fan(){cout << "Fan<T1, T2>" << endl;}
private:T1 _D1;T2 _D2;
};
//对于T1是double,T2是int时进行特化
template<>
class Fan<double, int>
{
public://构造函数Fan(){cout << "Fan<double, int>" << endl;}
private:double _D1;int _D2;
};

当参数为double、int时,编译器会匹配第二个类。


2.2.2偏特化

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

偏特化又可分为以下两种表现形式:『 部分特化』、『 参数更进一步的限制』。

(1)部分特化

我们可以仅对模板参数列表中的『 部分参数』进行确定化。

template<class T1, class T2>
class Fan
{
public://构造函数Fan(){cout << "Fan<T1, T2>" << endl;}
private:T1 _D1;T2 _D2;
};
//部分特化
template<class T1>
class Fan<T1, int>//将模板参数类表中的一部分参数特化
{
public://构造函数Fan(){cout << "Fan<T1, int>" << endl;}
private:double _D1;int _D2;
};

注意:当偏特化和全特化同时满足时,编译器会优先匹配全特化,因为偏特化还需要实例化其中的某个参数。


(2)参数更进一步的限制

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

比如:

//两个参数偏特化为指针类型
template<class T1, class T2>
class Fan<T1*, T2*>
{
public://构造函数Fan(){cout << "Fan<T1*, T2*>" << endl;}
private:T1 _D1;T2 _D2;
};
//两个参数偏特化为引用类型
template<class T1, class T2>
class Fan<T1&, T2&>
{
public://构造函数Fan(){cout << "Fan<T1&, T2&>" << endl;}
private:T1 _D1;T2 _D2;
};
  • 当模板参数都为指针类型时、会匹配第一个特化版本;
  • 当模板参数都为引用类型时、会匹配第二个特化版本;

3.模板的分离编译

 分离编译其实就是在项目中,声明与定义分离的代码方式。

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

 搭建一种场景用作讲解:

// a.h
template<class T>
T Add(const T& left, const T& right);
// a.cpp
template<class T>
T Add(const T& left, const T& right)
{return left + right;
}
// main.cpp
#include"a.h"
int main()
{Add(1, 2);Add(1.0, 2.0);return 0;
}

执行后:

分析:

提供模板就是为了让编译器自行生成对应的代码,可是这些文件在链接之前都是『 单独编译』的,如果声明和定义分离,编译器也就无从推导出对应的模板参数,从而导致『 无法实例化』,那最终链接时也就没有对应的实例化的函数即找不到定义,从而报错『 无法解析的外部符号』。

解决方法:

①在模板定义的位置显式实例化,可是这样太挫了,岂不是失去了模板的意义了,所以不推荐使用。

②将声明和定义放到一个文件中,一般命名为"xxx.hpp"或"xxx.h"。

  • .hpp和.h后缀是一样的,只不过是为了区分模板类和普通头文件,可以理解为一种『 命名习惯』。
  • 当未来你定义的类既有声明又有定义时,就命名为.hpp即可。

4.模板总结

优点:

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

缺陷:

  1. 模板会导致代码膨胀问题,也会导致编译时间变长。
  2. 出现模板编译错误时,错误信息非常凌乱,不易定位错误。推荐『 排除法』,注释掉可以代码的方式debug。

=========================================================================

如果你对该系列文章有兴趣的话,欢迎持续关注博主动态,博主会持续输出优质内容

🍎博主很需要大家的支持,你的支持是我创作的不竭动力🍎

🌟~ 点赞收藏+关注 ~🌟

========================================================================

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

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

相关文章

华为ensp--NAT实验

实验拓扑图及实验要求 实验相关配置 为保证可以登录防火墙web界面&#xff0c;需要对FW1、FW2以及Cloud1进行相关配置 Cloud1配置 需绑定网卡&#xff08;建议新建虚拟网卡&#xff09;&#xff0c;并且与防火墙管理口&#xff08;默认g0/0/0&#xff09;属于同一网段 FW1 F…

自动驾驶的决策层逻辑

作者 / 阿宝 编辑 / 阿宝 出品 / 阿宝1990 自动驾驶意味着决策责任方的转移 我国2020至2025年将会是向高级自动驾驶跨越的关键5年。自动驾驶等级提高意味着对驾驶员参与度的需求降低&#xff0c;以L3级别为界&#xff0c;低级别自动驾驶环境监测主体和决策责任方仍保留于驾驶…

【思路合集】talking head generation+stable diffusion

1 以DiffusionVideoEditing为baseline&#xff1a; 改进方向 针对于自回归训练方式可能导致的漂移问题&#xff1a; 训练时&#xff0c;在前一帧上引入小量的面部扭曲&#xff0c;模拟在生成过程中自然发生的扭曲。促使模型查看身份帧以进行修正。在像VoxCeleb或LRS这样的具…

ubuntu1604安装及问题解决

虚拟机安装vmbox7 虚拟机操作&#xff1a; 安装增强功能 sudo mkdir /mnt/share sudo mount -t vboxsf sharefolder /mnt/share第一次使用sudo提示is not in the sudoers file. This incident will be reported 你的root需要设置好密码 sudo passwd root 输入如下指令&#x…

机器学习整理

绪论 什么是机器学习&#xff1f; 机器学习研究能够从经验中自动提升自身性能的计算机算法。 机器学习经历了哪几个阶段&#xff1f; 推理期&#xff1a;赋予机器逻辑推理能力 知识期&#xff1a;使机器拥有知识 学习期&#xff1a;让机器自己学习 什么是有监督学习和无监…

【Java面试】Mysql

目录 sql的执行顺序索引的优点和缺点怎么避免索引失效(也属于sql优化的一种)一条sql查询非常慢&#xff0c;我们怎么去排查和优化&#xff1f;存储引擎 MylSAM和InnoDB、Memory的区别事务的四大特性(ACID)脏读、不可重复读、幻读事务的隔离级别&#xff1f;怎么优化数据库SQL优…

多个SSH-Key下,配置Github SSH-Key

首先&#xff0c;检查 github 的连接性&#xff0c;因为DNS污染的原因&#xff0c;很多机器ping不通github&#xff0c;就像博主的机器&#xff1a; 怎么解决DNS污染的问题&#xff0c;博主查了很多教程&#xff0c;测试出一个有效的方法&#xff0c;那就是修改hosts文件。host…

DAY11_(简易版)VUEElement综合案例

目录 1 VUE1.1 概述1.1.1 Vue js文件下载 1.2 快速入门1.3 Vue 指令1.3.1 v-bind & v-model 指令1.3.2 v-on 指令1.3.3 条件判断指令1.3.4 v-for 指令 1.4 生命周期1.5 案例1.5.1 需求1.5.2 查询所有功能1.5.3 添加功能 2 Element2.0 element-ui js和css和字体图标下载2.1 …

go语言(十九)---- channel

channel的使用 //1. 发送value到channelchannel <- value //2. 接收并将其丢弃<- channel //3. 从channel中接收数据&#xff0c;并将其赋值给x x : <- channel 例子 package mainimport "fmt"func main() {//定义一个channelc : make(chan int)go func…

山海鲸智慧医疗解决方案:让医疗数据说话

在医疗领域&#xff0c;数据可视化对于提高诊疗效率、辅助医学研究和提升患者就医体验具有重要意义。作为山海鲸可视化软件的开发者&#xff0c;我们致力于利用先进的数据可视化技术&#xff0c;为医疗行业提供高效、智能的解决方案&#xff0c;本篇文章就带大家一起了解一下这…

【Python】01快速上手爬虫案例一:搞定豆瓣读书

文章目录 前言一、VSCodePython环境搭建二、爬虫案例一1、爬取第一页数据2、爬取所有页数据3、格式化html数据4、导出excel文件 前言 实战是最好的老师&#xff0c;直接案例操作&#xff0c;快速上手。 案例一&#xff0c;爬取数据&#xff0c;最终效果图&#xff1a; 一、VS…

用Visual Studio Code创建JavaScript运行环境【2024版】

用Visual Studio Code创建JavaScript运行环境 JavaScript 的历史 JavaScript 最初被称为 LiveScript&#xff0c;由 Netscape&#xff08;Netscape Communications Corporation&#xff0c;网景通信公司&#xff09;公司的布兰登艾奇&#xff08;Brendan Eich&#xff09;在 …

SpringBoot 自定义Filter 提前返回 CORS 错误 处理前后端分离跨域配置无效问题解析

前言 浏览器有跨域限制&#xff0c;非同源策略 (协议、主机名或端口不同) 被视为跨域请求&#xff0c;解决跨域有跨域资源共享(CORS)、反向代理和 JSONP的方式。本篇通过 SpringBoot 的资源共享配置 (CORS) 来解决前后端分离项目的跨域&#xff0c;以及从原理上去解决跨域配置…

JVM简介

一、什么是JVM JVM是Java Virtual Machine&#xff08;Java虚拟机&#xff09;的缩写&#xff0c;JVM是一种用于计算设备的规范&#xff0c;它是一个虚构出来的计算机&#xff0c;是通过在实际的计算机上仿真模拟各种计算机功能来实现的。Java虚拟机包括一套字节码指令集、一组…

qt 坦克大战游戏 GUI绘制

关于本章节中使用的图形绘制类&#xff0c;如QGraphicsView、QGraphicsScene等的详细使用说明请参见我的另一篇文章&#xff1a; 《图形绘制QGraphicsView、QGraphicsScene、QGraphicsItem、Qt GUI-CSDN博客》 本文将模仿坦克大战游戏&#xff0c;目前只绘制出一辆坦克&#…

编译PCL Qt程序

使用PCL的qt程序时&#xff0c;提示不是用QVTK编译的&#xff0c;所以需要在编译VTK时打开Qt的编译选项&#xff08;由于CMakeList比较复杂&#xff0c;使用CMakeGui进行配置&#xff0c;PCL同理&#xff09;&#xff0c;编译VTK完成后&#xff0c;编译PCL也需要配置Qt支持&…

公司内网虚拟机中穿透服务器Coturn的搭建

1. 写在前面 coturn服务器的搭建文章已经非常多&#xff0c;但是对于对linux不熟悉的人来说排查错误的文章不多&#xff0c;此篇文章把我这次搭建过程以及如何排查问题做一个梳理我这里是在oracle vm虚拟机中搭建安装的ubuntu&#xff0c;通过H3C路由器映射到外网以下介绍我只…

再谈Android View绘制流程

一&#xff0c;先思考何时开始绘制 笔者在这里提醒读者&#xff0c;Android的View是UI的高级抽象&#xff0c;我们平时使用的XML文件也好&#xff0c;本质是设计模式中的一种策略模式&#xff0c;其View可以理解为一种底层UI显示的Request。各种VIew的排布&#xff0c;来自于开…

C语言之指针的地址和指向的内容总结(八十四)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

【开源】基于JAVA语言的实验室耗材管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 耗材档案模块2.2 耗材入库模块2.3 耗材出库模块2.4 耗材申请模块2.5 耗材审核模块 三、系统展示四、核心代码4.1 查询耗材品类4.2 查询资产出库清单4.3 资产出库4.4 查询入库单4.5 资产入库 五、免责说明 一、摘要 1.1…