C++模板(进阶)
文章目录
- 非类型模板参数
- 类模板的特化
- 类模板的概念
- 函数模板特化
- 类模板的特化
- 全特化
- 偏特化
- 参数的进一步限制
- 模板的分离编译
- 模板的优缺点
非类型模板参数
模板参数分类型形参与非类型形参.
类型形参: 出现在模板参数列表中,跟在class,typename之类的参数类型名称.
非类型形参: 就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用.
例如:
我们希望定义一个能够随时定义多个数组大小的静态数组,此时便可以通过非类型模板参数实现:
class Array
{
private:T _a[N];
};
int main()
{Array<int> a0; //定义一个大小为10的静态数组.Array<double, 100> a1;//定义一个大小为100的静态数组.Array<int, 1000> a2;//浮点数,类对象,字符串是不允许作为非类型模板参数的.
}
注意:
1:非类型模板参数只允许使用于整型,浮点型,类对象以及字}符串是不允许作为非类型模板参数的.
2:非类型模板参数在编译期就需要确认结果,因为编译器在编译阶段便根据非类型模板参数确定对应的类或者函数.
类模板的特化
类模板的概念
在原模版类的基础上,针对特殊类型所进行特殊化的实现方式,其中,模板特例化分为函数模板特化与类模板特化.
例如:
当我们不用类模板特化对日期类对象进行比较时会出现以下问题:
bool Less(T less, T right)
{return less < right;
}struct Date
{Date(int year, int month, int day):_year(year), _month(month), _day(day){}bool operator>(const Date& d) const{if ((_year > d._year)|| (_year == d._year && _month > d._month)|| (_year == d._year && _month == d._month && _day > d._day)){return true;}else{return false;}}bool operator<(const Date& d) const{if ((_year < d._year)|| (_year == d._year && _month < d._month)|| (_year == d._year && _month == d._month && _day < d._day)){return true;}else{return false;}}int _year;int _month;int _day;
};
int main()
{cout << Less(1, 2) << endl; //结果正确. 1Date d1(2022, 7, 7);Date d2(2022, 7, 8);cout << Less(d1, d2) << endl; //结果正确,1Date* p1 = &d1;Date* p2 = &d2;cout << Less(p1, p2) << endl; //结果错误,0return 0;}
Less对于绝大多数情况都可以正常比较,但是在特殊情况下就容易获得错误的答案,
p1指向的对象明显小于p2指向的对象,但是在Less内部中,并没有将p1指向的对象与p2指向的对象相比较,而是单纯的比较的是p1,p2指针的地址,而p1,p2的地址根据函数栈帧由高到低排布的,所以p1的地址比p2大,进而导致错误的结果.
函数模板特化
函数模板的特化步骤:
1: 必须要有一个基础的函数模板.
2: 关键字template后面要接一对尖括号,尖括号中指定需要特化的类型.
3: 函数形参表必须要与要模板函数的基础类型完全相同.
template<class T>
bool Less(T left, T right)
{return left < right;
}
//对Less函数模板进行特例化
template<>
//尖括号中需要指定特化的类型,且必须和模板函数的基础参数类型完全相同.
bool Less<Date*>(Date* left, Date* right)
{
//类模板特化将单纯指针的比较转换为Date对象的比较.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;
}
注意:
一般情况下,如果函数模板遇到不能处理或者处理有错误的类型,为了代码的可读性高,方便实现,对于一些复杂的函数模板,建议特化时特化给出.
template<class T>
bool Less(T left, T right)
{return left < right;
}
bool Less(Date* left, Date* right)
{return *left < *right;
}
类模板的特化
全特化
全特化时间模板参数列表中所有的参数都确定化.
指模板参数列表不写参数,在类名后面标注要传的类型,然后在定义中类型都用特例化的类型.
如果实参要传的类型与模板特例化的类型不一样,则在定义Date中会调用普通类模板.
template<class T1, class T2>
class Date
{
public:Date() { cout << "Data<T1, T2>" << endl;}
private:T1 _d1;T2 _d2;
};
template<>
class Date<int, char>
{
public:Date(){cout << "Data<int, char>" << endl;}
private:int _d1;char _d2;
};
int main()
{Date<int, char>d1; //走的是函数模板特例化.Date<int, int> d2; //走的是函数模板.
}
偏特化
指的是将模板参数列表的一部分参数进行特化.
class Date
{
public://构造函数Date(){cout << "Date<T1, T2>" << endl;}
private:T1 _d1;T2 _d2;
};
template < class T1 >
class Date < T1, int >
{
public:Date(){cout << " Data < T1, int > " << endl;}
private:T1 _d1;int _d2;
};int main()
{Date <int, int > d1;Date <int, char > d2;return 0;
}
参数的进一步限制
偏特化不仅仅是指特化部分参数,而是针对模板参数更进一步的条件限制所设计出来的一个特化版本.
template <typename T1, typename T2>
class Date <T1*, T2*>
{
public:Date(){ cout << "Data<T1*, T2*>" << endl;}
private:T1 _d1;T2 _d2;
};
//两个参数偏特化为引用类型
template <typename T1, typename T2>
class Date <T1&, T2&>
{
public:Date(const T1& d1, const T2& d2): _d1(d1), _d2(d2){cout << "Data<T1&, T2&>" << endl;}private:const T1 _d1;const T2 _d2;
};
int main()
{
// Data<double, int> d1; // 调用特化的int版本
// Data<int, double> d2; // 调用基础的模板 Date<int*, int*> d3;Date<int&, int&> d4(1,2);
}
这,当实例化对象模板参数为指针类型或者引用类型时,编译器会根据模板参数最匹配的进行调用.

模板的分离编译
例如:
我们将v.push_back函数模板声明与定义分别放进.h和.cpp文件中,
而vector构造,operator[]等成员函数声明与定义放到vector.h文件中,
此时在编译阶段,这些成员函数就已经实例化了从而确定函数地址了.
可是,push_back函数模板声明与定义是分开的,导致在编译阶段就无法确定T的参数类型,也就说明只有函数声明没有函数定义了,那么函数地址只能从链接阶段去找,可是,没有函数定义,也就无法将函数地址放进符号表中,编译器无法在符号表中根据函数声明去寻找对应的函数地址了.
#include <vector>
int main()
{vector<int> v;v.push_back(1);v.push_back(2);return 0;
}
解救办法:
1:类模板以及类模板函数什么声明与定义不要分离编译.
2: 类模板显示实例化具体的类型:int,double(编译器就可以找编译中将函数模板实例化了)
模板的优缺点
注意:
我们不推荐显示显示类模板的具体类型,因为如果是别的数据类型又要重新显示实例化.
优点:
模板复用了代码,节省资源,更快的迭代开发,C++的标准模板库(STL)因此而产生。(将重复的工作交给编译器做),增强了代码的灵活性。
缺陷:
1:模板会导致代码膨胀问题(实例化多少就会有多少份代码),也会导致编译时间变长。
2:出现模板编译错误时,错误信息非常凌乱,不易定位错误。
相关文章:
C++模板(进阶)
文章目录非类型模板参数类模板的特化类模板的概念函数模板特化类模板的特化全特化偏特化参数的进一步限制模板的分离编译模板的优缺点非类型模板参数 模板参数分类型形参与非类型形参. 类型形参: 出现在模板参数列表中,跟在class,typename之类的参数类型名称. 非类型形参: 就是…...
【数据分析之道(二)】列表
文章目录专栏导读1、列表介绍2、访问列表中的值3、列表增加和修改4、删除元素5、列表函数6、列表方法专栏导读 ✍ 作者简介:i阿极,CSDN Python领域新星创作者,专注于分享python领域知识。 ✍ 本文录入于《数据分析之道》,本专栏针…...
架构师必须要掌握的大小端问题
一、什么是大端和小端 所谓的大端模式,就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。 所谓的小端模式,就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。 简单来说:大端——高尾端,小端——低尾端 举个例子,比如数字 0x12 34 56 78…...
2023年ACM竞赛班 2023.3.20题解
目录 瞎编乱造第一题 瞎编乱造第二题 瞎编乱造第三题 瞎编乱造第四题 瞎编乱造第五题 不是很想编了但还是得编的第六题 不是很想编了但还是得编的第七题 还差三道题就编完了的第八题 还差两道题就编完了的第九题 太好啦终于编完了 为啥一周六天早八阿 瞎编乱造第一题…...
什么是语法糖?Java中有哪些语法糖?
本文从 Java 编译原理角度,深入字节码及 class 文件,抽丝剥茧,了解 Java 中的语法糖原理及用法,帮助大家在学会如何使用 Java 语法糖的同时,了解这些语法糖背后的原理1 语法糖语法糖(Syntactic Sugar&#…...
STM32学习(五)
GPIO General Purpose Input Output,通用输入输出端口,简称GPIO。 作用: 采集外部器件的信息(输入)控制外部器件的工作(输出) GPIO特点 1,不同型号,IO口数量可能不一样…...
STM32的CAN总线调试经验分享
相关文章 CAN总线简易入门教程 CAN总线显性电平和隐性电平详解 STM32的CAN总线调试经验分享 文章目录相关文章背景CAN总线CAN控制器CAN收发器调试过程硬件排查CAN分析仪芯片CAN控制器调试总结背景 最近负责的一个项目用的主控芯片是STM32F407IGT6,需要和几个电机控…...
深度剖析自定义类型(结构体、枚举、联合)——“C”
各位CSDN的uu们你们好呀,今天,小雅兰的内容是心心念念的结构体啦,其实在此之前,我也写过结构体的知识点,只是并没有很深入,那么,今天我会仔细来学习自定义类型的知识点,下面…...
《水经注地图服务》发布的全球影像数据在水经微图中调用
(本文首发于“水经注GIS”公号,订阅“水经注GIS”公号,为你分享更多GIS技术 )1、引言古人云:“工欲善其事,必先利其器。”意思是说:工匠想要使他的工作做好,一定要先让工具锋利&…...
MyBatis --- 缓存、逆向工程、分页插件
一、MyBatis的缓存 1.1、MyBatis的一级缓存 一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就会从缓存中直接获取,不会从数据库重新访问 使一级缓存失效的四种情况: 1、…...
vue3自定义svg图标组件
可参考: 未来必热:SVG Sprites技术介绍 懒人神器:svg-sprite-loader实现自己的Icon组件 在Vue3项目中使用svg-sprite-loader 前置知识 在页面中,虽然可以通过如下的方式使用img标签,来引入svg图标。但是,…...
智能火焰与烟雾检测系统(Python+YOLOv5深度学习模型+清新界面)
摘要:智能火焰与烟雾检测系统用于智能日常火灾检测报警,利用摄像头画面实时识别火焰与烟雾,另外支持图片、视频火焰检测并进行结果可视化。本文详细介绍基于智能火焰与烟雾检测系统,在介绍算法原理的同时,给出Python的…...
Java实习生------JUC并发编程(多线程)10道面试题打卡⭐⭐⭐
目录 并行和并发有什么区别? 线程和进程有什么区别? 创建线程有哪几种方式? runnable和callable有什么区别? 线程的状态及转换? sleep()和wait()的区别? run()和start()有什么区别? 在…...
ChatGPT和百度文心一言写用例,谁更强?
文心一言发布的第一时间,就排队申请了邀请码,昨晚看了下,邀请码已经到手,索性就拿一个例子试了一下,看看哪个能够真正意义上的提高生产力,最简单的录制了个GIF动画如下:问题:你是一个…...
设计模式总结
设计模式的六大原则 开放-封闭原则(OCP) (总原则) Open-Close Principle:该对扩展开放,对修改关闭。 目的就是保证程序的扩展性好,易于维护和升级。 开放-封闭原则是面向对象设计的核心所在, 开闭原则是Java世界里最基础的设计原则。 开闭…...
【K8S系列】深入解析Pod对象(一)
目录 序言 1.问题引入 1.1 问题描述 2 问题解答 2.1 pod 属性 2.1.1 NodeSelector 2.1.2 HostAliases 2.1.3 shareProcessNamespace 2.1.4 NodeName 2.1.5 其他pod属性 2.2 容器属性 2.2.1 ImagePullPolicy 2.2.2 Lifecycle 3 总结 4. 投票 序言 任何一件事情&am…...
JVM学习.02 内存分配和回收策略
1、前言《JVM学习.01 内存模型》篇讲述了JVM的内存布局,其中每个区域是作用,以及创建实例对象的时候内存区域的工作流程。上文还讲到了关于对象存货后,会被回收清理的过程。今天这里就着重讲一下对象实例是如何被清理回收的,以及清…...
logstash+elasticsearch+Kibana(ELK)日志收集
文章目录一.安装ELK 7.17二.为Elasticsearch设置密码三.配置logstash四.springboot整合logstash五.spring整合Elastic Search一.安装ELK 7.17 不要一股脑执行以下语句,请观察修改要修改的地方 安装logstash # logstash安装docker run -d --name logstash \-p 5043:5043 -p 5…...
今天面试了一个2年Java经验的
今天去面试了一个26岁的程序员,看了简历,2年经验,本科,写得很牛叉。 Spring cloud alibaba全家桶、redis,分布式锁,服务调用,数据库事务,线程,Zookeeper、Dubbo 、Rabbi…...
逻辑覆盖测试用例设计
逻辑覆盖测试用例设计 实验目标 能够依据程序画出程序流程图理解常用覆盖方法的内涵理解常用覆盖方法的强弱关系能够使用常用覆盖方法设计测试用例 背景知识 白盒测试通常采用静态测试方法和动态测试方法开展。动态测试是参照系统需求或测试规则,通过预先设计一…...
系统架构设计师常见高频考点总结之数据库
1. 局部数据库缓存1.1. 如何避免单点故障?(高可用设计)只要题目提到“避免单点故障”或“高可靠性”,标准答案只有一套组合拳:冗余(Redundancy):一台不够就两台。热备(Ho…...
Hunyuan-MT-7B效果实测:Pixel Language Portal对中文网络用语、方言、谐音梗的跨维转码能力分析
Hunyuan-MT-7B效果实测:Pixel Language Portal对中文网络用语、方言、谐音梗的跨维转码能力分析 1. 引言:当翻译遇上像素冒险 在数字时代的语言交流中,传统翻译工具往往显得生硬而缺乏温度。Pixel Language Portal(像素语言跨维…...
FireRedASR Pro在微信小程序开发中的应用:实时语音输入与转写
FireRedASR Pro在微信小程序开发中的应用:实时语音输入与转写 不知道你有没有这样的经历:用手机打字回复长消息时,手指按得发酸;或者在线听课时,想快速记下老师的重点,手速却跟不上语速。在移动优先的今天…...
SystemVerilog实战:在Vivado 2023.1中实现跨文件clog2计算的3种方法
SystemVerilog实战:在Vivado 2023.1中实现跨文件clog2计算的3种方法 当我们将传统Verilog项目迁移到SystemVerilog环境时,经常会遇到$clog2函数的兼容性问题。这个看似简单的对数计算函数,在不同工具链和文件类型中的表现可能大相径庭。特别是…...
告别手动操作!Open-AutoGLM让iPhone听懂人话,自动执行指令
告别手动操作!Open-AutoGLM让iPhone听懂人话,自动执行指令 1. 引言 你是否厌倦了每天重复点击手机屏幕的操作?是否希望手机能像真人助理一样理解你的需求并自动完成任务?今天我要介绍的Open-AutoGLM正是这样一个革命性的AI手机智…...
stealth.js全解析:40+反检测补丁的配置与优化技巧
Stealth.js全解析:40反检测补丁的配置与优化技巧 在当今的Web自动化领域,反检测技术已成为开发者必须掌握的核心技能之一。无论是数据采集、自动化测试还是其他需要模拟真实用户行为的场景,如何让脚本"隐形"都是决定成败的关键因素…...
如何快速掌握Mermaid在线编辑器:面向初学者的完整可视化工具指南
如何快速掌握Mermaid在线编辑器:面向初学者的完整可视化工具指南 【免费下载链接】mermaid-live-editor Edit, preview and share mermaid charts/diagrams. New implementation of the live editor. 项目地址: https://gitcode.com/GitHub_Trending/me/mermaid-l…...
【算法实战】分支限界法解电路布线:从理论到代码实现
1. 电路布线问题与分支限界法初探 电路布线问题就像是在一个布满障碍物的迷宫中寻找最短路径。想象一下,你手里拿着一根电线,需要在布满元件的电路板上找到一条最短的路径连接两个点,而且电线只能走直线或者直角转弯。这就是电路布线问题的现…...
Meta2d.js完整指南:5步掌握专业级2D可视化引擎开发
Meta2d.js完整指南:5步掌握专业级2D可视化引擎开发 【免费下载链接】meta2d.js The meta2d.js is real-time data exchange and interactive web 2D engine. Developers are able to build Web SCADA, IoT, Digital twins and so on. Meta2d.js是一个实时数据响应和…...
从云中心到边缘节点,Java Runtime冷启动优化全解析,将延迟压至87ms以内
第一章:Java边缘运行时部署的演进与挑战随着物联网、5G和实时AI推理场景的爆发式增长,Java应用正加速向边缘侧迁移。然而,传统JVM设计面向服务器长期运行环境,其启动延迟高、内存占用大、冷启动慢等特性与边缘设备资源受限、事件驱…...
