C++模板进阶
一、非类型模板参数
模板参数分为:类型形参、非类型形参
类型形参:class与typename都是参数类型
非类型形参:用一个常量作为模板的一个参数,一般是整型常量
#include<iostream>
#include<array>
using namespace std;//class T为类型模板参数,用于适配各种类型
//size_ t N为非类型模板参数,只能为整型常量
template<class T,size_t N>//下面的size_t N虽然没有加const但默认为常量
class Array
{
public:
private:T _a[N];
};template<class T,size_t N=10>
//template<class T,double N=10>//会报错,类型非法
void func(const T& a)
{N = 20;//会报错必须为可操作得左值,说明N非类型模板参数为常量
}int main()
{//非类型模板参数可以对不同得对象开辟不同大小的空间Array<int,10> a1;Array<double,20> a2;int arr[15];array<float, 15> a3;//C++11中更新的容器,对标C语言中的静态数组//不提供初始化,但是有严格的越界检查,读写全面检查}
1.浮点数、类对象以及字符串是不允许作为非类型模板参数的
2.非类型模板参数必须在编译器就能确认
二、模板特化
模板对于一些特殊类型可能会产生一些错误的结果
就比如下面实现的比较大小的代码,对于Date类的特定对象可以实现对比功能,但是如果使用特定对象的指针进行比较,就会产生错误
因此需要使用模板进行特化,也就是在原来模板的基础上,对特殊类型进行特殊化处理
#include<iostream>
using namespace std;class Date
{
public:Date(int year = 1900, int month = 1, int day = 1): _year(year), _month(month), _day(day){}bool operator<(const Date& d)const{return (_year < d._year) ||(_year == d._year && _month < d._month) ||(_year == d._year && _month == d._month && _day < d._day);}bool operator>(const Date& d)const{return (_year > d._year) ||(_year == d._year && _month > d._month) ||(_year == d._year && _month == d._month && _day > d._day);}friend ostream& operator<<(ostream& _cout, const Date& d){_cout << d._year << "-" << d._month << "-" << d._day;return _cout;}private:int _year;int _month;int _day;
};template<class T>
bool Less(T left, T right)
{return left < right;
}int main()
{cout << Less(1, 5) << endl;//1 可以比较,结果正确Date d1(2023, 5, 10);Date d2(2023, 5, 1);cout << Less(d1, d2) << endl;//0 可以比较,结果正确Date* p1 = &d1;Date* p2 = &d2;cout << Less(p1, p2) << endl;//1 可以比较,结果错误return 0;
}
可以参数Less函数一般都可以进行正常比较,但是以如上代码为例,进行自定义对象的对比正常,但是对于指向自定义类型对象的指针对比错误。因此需要特化
1.函数模板特化
函数模板的特化步骤:
1. 必须要先有一个基础的函数模板
2. 关键字template后面接一对空的尖括号<>
3. 函数名后跟一对尖括号,尖括号中指定需要特化的类型
4. 函数形参表: 必须要和模板函数的基础参数类型完全相同,如果不同编译器可能会报一些奇怪的错误
函数模板特化使用较少,因为可以直接给出特定的函数用于实现,也就是函数重载
#include<iostream>
using namespace std;class Date
{
public:Date(int year = 1900, int month = 1, int day = 1): _year(year), _month(month), _day(day){}bool operator<(const Date& d)const{return (_year < d._year) ||(_year == d._year && _month < d._month) ||(_year == d._year && _month == d._month && _day < d._day);}bool operator>(const Date& d)const{return (_year > d._year) ||(_year == d._year && _month > d._month) ||(_year == d._year && _month == d._month && _day > d._day);}friend ostream& operator<<(ostream& _cout, const Date& d){_cout << d._year << "-" << d._month << "-" << d._day;return _cout;}private:int _year;int _month;int _day;
};template<class T>
bool Less(T left, T right)
{return left < right;
}//函数模板特化--对某些类型进行特殊化处理
template<>
bool Less<Date*>(Date* left, Date* right)//全特化
{return *left < *right;
}//实例化重载
bool Less(Date* left, Date* right)
{return *left < *right;
}void test_1()
{cout << "Less" << endl;cout << Less(1, 2) << endl;Date d1(2023, 5, 10);Date d2(2023, 5, 5);cout << Less(d1, d2) << endl;Date* p1 = &d1;Date* p2 = &d2;cout << Less(p1, p2) << endl;//调用特化之后的版本,不通过模板生成
}int main()
{test_1();return 0;
}
2.类模板特化
类模板特化分为全特化和偏特化
全特化:即是将模板参数列表中所有的参数都确定化
偏特化:对模板参数进行限制的特化版本
全特化可以理解为所有参数都锁定的特化,偏特化可以理解为部分参数特化
#include<iostream>
using namespace std;//类模板
template<class T1,class T2>
class modle
{
public:modle(){cout << "modle<T1,T2>" << endl;}
private:T1 _m1;T2 _m2;
};//类模板全特化
template<>
class modle<int,char>
{
public:modle(){cout << "modle<T1,T2>" << endl;}
private:int _m1;char _m2;
};//偏特化
template<class T1>
class modle<T1, int>//将模板参数列表的一部分参数特化,将第二个参数转化为int
{
public:modle(){cout << "modle<T1,int>" << endl;}
private:T1 _m1;int _m2;
};//将两个参数偏特化为指针类型
template<typename T1,typename T2>
class modle<T1*, T2*>
{
public:modle(){cout << "modle<T1*,T2*>" << endl;}
private:T1 m1;T2 m2;
};//将两个参数偏特化为引用类型
template<typename T1, typename T2>
class modle<T1&, T2&>
{
public:modle(const T1& m1,const T2& m2):_m1(m1),_m2(m2){cout << "modle<T1&,T2&>" << endl;}
private:const T1& _m1;const T2& _m2;
};void test_2()
{modle<int, int> m1;//偏特化的部分参数特化版本modle<int,char> m2;//全特化modle<int*, int*> m3;//偏特化的指针版本modle<int&, int&> m4(1, 5);//偏特化的引用版本
}int main()
{test_2();return 0;
}
三、模板的分离编译
一个项目由若干个源文件共同实现,每个源文件会独立线性生成相应的预处理文件(.i),编译文件(.s),汇编文件(.o),最后再将所有目标文件链接,形成单一的可执行文件的过程为分离编译模式
func.h
#pragma once
#include<iostream>
#include<array>
#include <vector>
using namespace std;template<class T>
T Add(const T& left, const T& right);template<class T>
T Add(const T& left, const T& right)
{return left + right;
}// 声明和定义放到一起,直接就可以实例化,编译时就有地址,不需要链接void func();
//模板不支持声明与定义不在同一个文件
//但是模板支持在一个文件内部,声明和定义分离#include"func.h"
template<class T>
T Add(const T& left, const T& right)
{return left + right;
}void func()
{cout << " void func()" << endl;
}//显式实例化,此时编译时就知道需要实例化一个double类型的Add函数
template
double Add<double>(const double& left, const double& right);
//但是这样对于其他类型需要不断得显示实例化,十分麻烦
工程只有再链接的时候才会寻找函数地址,但是函数模板只有在调用的时候才会产生实例化,因此再没有实例化的时候并没有地址,在链接时会产生报错
解决方法:
1.将声明和定义放在同一个文件内,一般都是统一放在头文件内
2.模板定义的位置显示实例化,对于多个不同类型调用十分麻烦,不建议使用
模板总结
优点 | 缺点 |
模板复用代码,节省资源,使得代码简明高效 | 模板会导致代码膨胀,对于不同的类型进行不同的实例化,会导致编译时间变长 |
增强的代码的灵活性 | 出现模板编译错误时,错误信息凌乱,不易定位 |
相关文章:

C++模板进阶
一、非类型模板参数 模板参数分为:类型形参、非类型形参 类型形参:class与typename都是参数类型 非类型形参:用一个常量作为模板的一个参数,一般是整型常量 #include<iostream> #include<array> using namespace …...

【人力资源管理】第4集 免费开源ERP: Odoo 16 Appraisal员工绩效评估 构建一体化企业人力资源管理
文章目录 前言一、概览二、主要功能1.设置定期的员工评估2.构建正确的评估3.设计您自己的调查4.自动评估过程 总结 前言 在员工工作中创建评估。同时审查员工表现。 一、概览 员工评价 评估内容 目标制定 评价指标 评价分析 二、主要功能 1.设置定期的员工评估 强化贵公司的…...

「AI 孙燕姿」翻唱华语乐坛歌曲爆红全网,AI 翻唱将带来哪些影响?是否会有版权等问题?
在某视频平台上,“AI孙燕姿”成了新网红,它翻唱过周杰伦的《发如雪》、翻唱过郭顶的《水星记》、翻唱过赵雷的《我记得》,受到了网友的追捧,甚至有网友宣布“这是2023年最火的声音”。 网上除了AI孙燕姿,还有AI周杰伦…...

路径规划算法:基于灰狼优化的路径规划算法- 附代码
路径规划算法:基于灰狼优化的路径规划算法- 附代码 文章目录 路径规划算法:基于灰狼优化的路径规划算法- 附代码1.算法原理1.1 环境设定1.2 约束条件1.3 适应度函数 2.算法结果3.MATLAB代码4.参考文献 摘要:本文主要介绍利用智能优化算法灰狼…...

推荐系统综述
目录 推荐系统架构1、传统推荐方式1.1 基于内容推荐(Content-Based recommendation,CB)1.2 协同过滤推荐(Collaborative Filtering recommendation, CF)1.2.0 UserCF举例:1. 2. 1 基于内存的推荐…...

SQLIST数据库编程
目录 数据库简介 1.常用数据库 2. SQLite基础 3.创建SQLite数据库 虚拟中sqlite3安装 基础SQL语句使用 sqlite3编程 数据库简介 1.常用数据库 大型数据库 :Oracle 中型数据库 :Server是微软开发的数据库产品,主要支持windows平台 小型数据库…...

vue2中操作对象的方法
在 Vue2 中,我们可以使用以下方法来操作对象: Vue.set(object, key, value):用于在 Vue 实例中添加响应式属性。它会确保添加的属性是响应式的,并触发视图更新。 Vue.delete(object, key):用于从 Vue 实例中删除属性。…...

左值引用、右值引用,std::move() 的汇编解释
1:左值引用 引用其实还是指针,但回避了指针这个名字。由编译器完成从地址中取值。以vs2019反汇编: 如图,指针和引用的汇编代码完全一样。但引用在高级语言层面更友好,对人脑。比如可以少写一个 * 号和 -> 。 &…...

LiangGaRy-学习笔记-Day11
LiangGaRy-学习笔记-Day11 1、课前回顾 1.1、脚本回顾讲解 题目: 脚本实现搭建LAMP架构可以写一段,后试一段引入变量、函数、尝试增删改查手工执行一遍 [rootNode1 ~]# vim auto_lanmp.sh #!/bin/bash #Author By LiangGaRy #2023年5月7日 #Usage …...

【异常解决】浏览器无法访问此网站ERR_UNSAFE_PORT/网页可能无法连接,或者它已永久性地移动到了新网址问题解决方案
浏览器无法访问此网站ERR_UNSAFE_PORT问题解决方案 一、问题描述二、问题原因三、解决方案3.1 方案1修改服务器访问端口号(推荐)3.2 方案2修改浏览器设置3.2.1 Chrome浏览器3.2.2 Firefox浏览器3.2.3 Edge浏览器 一、问题描述 访问某一个特定的网址之后…...

Python函数的参数
定义一个函数非常简单,但是怎么定义一个函数,需要什么参数,怎么去调用却是我们需要去思考的问题。 如同大多数语言一样(如 Java),Python 也提供了多种参数的设定(如:默认值参数、关…...

【Hive大数据】Hive分区表与分桶表使用详解
目录 一、分区概念产生背景 二、分区表特点 三、分区表类型 3.1 单分区 3.2 多分区 四、动态分区与静态分区 4.1 静态分区【静态加载】 4.1.1 操作演示 4.2 多重分区 4.2.1 操作演示 4.3 分区数据动态加载 4.3.1 分区表数据加载 -- 动态分区 4.3.2 操作演示 五、…...

C#NPOI操作Excel详解
C# NPOI 是一个基于 .NET Framework 的 Excel 和 Word 操作库。它不仅可以读取和写入 Excel 和 Word 文件,还可以对 Excel 和 Word 文件进行格式化和样式编辑,支持多种常见的文件格式,如XLS,XLSX等。本篇文章将针对C# NPOI操作Exc…...

CSS中文字体 Unicode 编码表
一、简介 CSS(层叠样式表)是用于样式化Web页面的强大工具,它可以用来控制页面的外观和行为。在CSS中,可以使用多种字体来设置文本的外观和格式,包括中文字体。中文字体的实现需要引入相应的字体文件,并且需…...

《微服务实战》 第四章 Spring Cloud Netflix 之 Eureka
前言 Eureka 是 Netflix 公司开发的一款开源的服务注册与发现组件。 Spring Cloud 使用 Spring Boot 思想为 Eureka 增加了自动化配置,开发人员只需要引入相关依赖和注解,就能将 Spring Boot 构建的微服务轻松地与 Eureka 进行整合。 1、Eureka 两大组…...

11. 深入理解并发编程-AQS与JMM
AQS (AbstractQueuedSynchronizer) 他的实现类诸如: CountDownLatch、ThreadLocalPool和ReentrantLock 在这些类中,AQS都是以内部类的形式存在的 AQS使用了模板方法设计模式 例子: 做蛋糕分为3个步骤,定一个抽象类,重写3个方法,做模型、烘焙和涂抹原料,然后在另外1个方法做蛋糕…...

深度解耦:使用Jetpack新技术Hilt实现依赖注入
注入解耦是一种软件设计模式,旨在将应用程序的不同组件解耦。通过采用依赖注入、控制反转、面向接口编程等技术,注入解耦模式可以帮助开发人员将应用程序分解为可重用和可扩展的组件。这样做可以减少代码的耦合度,提高模块化和可测试性&#…...

C++ 构造函数-2
构造函数-2 构造函数体赋值 在对象创建的时候,编译器会调用构造函数,给对象当中的成员赋一个合适的初始值。 class Date { public: Date(int year, int month, int day) { _year year; _month month; _day day; } private: int _year; int _month; i…...

网安笔记 08 key management
Key Management —— 不考 网络加密方法 1.1 链路加密 特点: 两个相邻点之间数据进行加密保护 不同节点对密码机和Key不一定同中间节点上,先解密后加密报文报头可一起加密节点内部,消息以明文存在密钥分配困难保密及需求数量大 缺点&…...

Linux socket
百度百科对于Socket的介绍 套接字(socket)是一个抽象层,应用程序可以通过它发送或接收数据,可对其进行像对文件一样的打开、读写和关闭等操作。套接字允许应用程序将I/O插入到网络中,并与网络中的其他应用程序进行通信…...

14.构造器的排序分组.子查询
学习要点: 1.排序分组 2.子查询 本节课我们来开始学习数据库的构造器查询中的子查询、排序、分组等。 一.排序分组 1. 使用 whereColumn()方法实现两个字段相等的查询结果; //判断两个相等的字段,同样支持 orWhereColumn() //支持…...

【剑指 Offer】05,替换字符创中的空格;难度等级:简单。易错点:C++中 char 和 string 类型的转换
【剑指 Offer】05,替换字符创中的空格;难度等级:简单。 文章目录 一、题目二、题目背景三、我的解答四、易错点五、知识点:char 和 string 类型的转换 一、题目 二、题目背景 在网络编程中,如果 URL 参数中含有特殊字…...

图像分割入门教程
文章目录 图像分割入门教程1. 图像分割基本概念2. 基于阈值的图像分割3. 基于区域的图像分割4. 基于边缘的图像分割5. 基于区域和边缘的图像分割区别6. 基于深度学习的图像分割7. 实现步骤结论 图像分割入门教程 图像分割是计算机视觉领域的一个重要任务,其目标是将…...

C++入门教程||C++ 信号处理||C++ 多线程
C 信号处理 C 信号处理 信号是由操作系统传给进程的中断,会提早终止一个程序。在 UNIX、LINUX、Mac OS X 或 Windows 系统上,可以通过按 CtrlC 产生中断。 有些信号不能被程序捕获,但是下表所列信号可以在程序中捕获,并可以基于…...

java计算矩形的面积和周长的方法
在生活中,我们常常需要计算某个矩形的面积和周长,如我们经常用的计算器就是个不错的选择,它可以计算出任意一个矩形的面积和周长。那么,如果你想使用 Java编程语言来计算矩形的面积和周长,你该如何做呢?今天…...

一分钟掌握如何更换Jupyter Notebook的主题和字体
Jupyter Notebook 更换主题(背景、字体) 在现代科技发展的浪潮中,Jupyter Notebook 作为一种强大的交互式笔记工具,已经被越来越多的用户所使用。它以其简单易用、功能强大、资源丰富等特点,成为了许多人学习、工作、科…...

如何系统全面的自学自动化测试?明确后我直接拿到了20K
玩自动化测试多年的老司机带你上车全面系统学习自动化测试,并且还能教你如何学习才能在今年拿到一份不错的offer。 说到系统全面,就是以目前绝大部分公司招聘要求的知识内容为基准,毕竟我们学习自动化测试都是为了高薪工作,《史记…...

【搭建私有云盘】无公网IP,在外远程访问本地微力同步
文章目录 1.前言2. 微力同步网站搭建2.1 微力同步下载和安装2.2 微力同步网页测试2.3 cpolar的安装和注册 3.本地网页发布3.1 Cpolar云端设置3.2 Cpolar本地设置 4. 公网访问测试5. 结语 1.前言 私有云盘作为云存储概念的延伸,虽然谈不上多么新颖,但是其…...

Pytest自动化测试框架一些常见的插件
Pytest拥有丰富的插件架构,超过800个以上的外部插件和活跃的社区,在PyPI项目中以“ pytest- *”为标识。 本篇将列举github标星超过两百的一些插件进行实战演示。 插件库地址:http://plugincompat.herokuapp.com/ 1、pytest-htmlÿ…...

【力扣】刷题+剑指offer第二版
文章目录 题目收藏不含重复字符的最长子串最长公共子串 剑指 Offer剑指 Offer 05. 替换空格剑指 Offer 03. 数组中重复的数字剑指 Offer 04. 二维数组中的查找剑指 Offer 09. 用两个栈实现队列剑指 Offer 07. 重建二叉树剑指 Offer 06. 从尾到头打印链表剑指 Offer 11. 旋转数组…...