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插入到网络中,并与网络中的其他应用程序进行通信…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...

【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...

ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...
Python 包管理器 uv 介绍
Python 包管理器 uv 全面介绍 uv 是由 Astral(热门工具 Ruff 的开发者)推出的下一代高性能 Python 包管理器和构建工具,用 Rust 编写。它旨在解决传统工具(如 pip、virtualenv、pip-tools)的性能瓶颈,同时…...

Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...

计算机基础知识解析:从应用到架构的全面拆解
目录 前言 1、 计算机的应用领域:无处不在的数字助手 2、 计算机的进化史:从算盘到量子计算 3、计算机的分类:不止 “台式机和笔记本” 4、计算机的组件:硬件与软件的协同 4.1 硬件:五大核心部件 4.2 软件&#…...

R 语言科研绘图第 55 期 --- 网络图-聚类
在发表科研论文的过程中,科研绘图是必不可少的,一张好看的图形会是文章很大的加分项。 为了便于使用,本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中,获取方式: R 语言科研绘图模板 --- sciRplothttps://mp.…...
django blank 与 null的区别
1.blank blank控制表单验证时是否允许字段为空 2.null null控制数据库层面是否为空 但是,要注意以下几点: Django的表单验证与null无关:null参数控制的是数据库层面字段是否可以为NULL,而blank参数控制的是Django表单验证时字…...