类似于微博网站怎么做的/免费seo搜索优化
在前面的文章中,我们已经简单的了解了模板的使用,在这篇文章中,我们将继续深入探讨模板
1.模板的特化
1.1 概念
通常情况下,使用模板可以实现一些与类型无关的代码,但对于一些特殊类型的可能会得到一些错误的结果,需要特殊处理,比如:实现一个专门用来进行小于比较的函数模板
#include <iostream>
using namespace std;
template <class T>
bool LESS(T left, T right)
{return left < right;
}
class date
{
public:date(int year =2025,int month=2,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);}
private:int _year;int _month;int _day;
};
int main()
{cout << LESS(1, 2) << endl; // 可以比较,结果正确cout << LESS(2, 1) << endl; // 可以比较,结果正确//日期类(自定义类型)也可以date d1(2025, 4, 20);date d2(2025, 1, 7);cout << LESS(d1, d2) << endl;return 0;
}
但是,倘若我们要这样比较,结果就不一定正确了,因为这里我们在比较地址,而不是比较内容本身!
因此,我们要对模板进行特化, 使得上述例子得以正确执行!
1.2 函数模板特化
函数模板的特化步骤:
1. 必须要先有一个基础的函数模板
2. 关键字template后面接一对空的尖括号<>
3. 函数名后跟一对尖括号,尖括号中指定需要特化的类型
4. 函数形参表: 必须要和模板函数的基础参数类型完全相同,如果不同编译器可能会报一些奇怪的 错误。
template <class T>
bool LESS(T left, T right)
{return left < right;
}
template<>
bool LESS<date*>(date* left, date* right)
{return *left < *right;
}
int main()
{date d1(2050, 4, 20);date d2(2022, 1, 7);date* p1 = &d1;date* p2 = &d2;cout << LESS(p1, p2) << endl;return 0;
}
这样,那个指针的例子便可以通过了!因为其将调用特化之后的版本,而不走原来的模板了!
但是,我们之前就学过函数,这样在写一个函数模板,显得多此一举了,不如直接写一个函数,还省事!
bool LESS(date* d1, date* d2)
{return *d1 < *d2;
}
int main()
{date d1(2002, 4, 20);date d2(2022, 1, 7);date* p1 = &d1;date* p2 = &d2;cout << LESS(p1, p2) << endl;return 0;
}
结论:函数模板不建议特化。
1.3 类模板特化
1.3.1 全特化
全特化即是将模板参数列表中所有的参数都确定化
//总的模板
template <class T1,class T2>
class rens
{
public:rens() { cout << "rens<t1,t2>" << endl; }
private:T1 _r1;T2 _r2;
};
//全特化
template<>
class rens<int*, int*>
{
public:rens() { cout << "rens<int*,int*>" << endl; }
};
template<>
class rens<int, char>
{
public:rens() { cout << "rens<int, char>" << endl; }
//这个私有写不写都行,个人不喜欢写
private:int r1;char r2;
};
template<>
class rens<char, int>
{
public:rens() { cout << "rens<char,int>" << endl; }
//这个私有写不写都行,个人不喜欢写
private:char r1;int r2;
};
int main()
{rens<int, char> r1;rens<int*,int> r2;rens<char, int> r3;rens<int*, int*> r4;return 0;
}
运行结果如下:
结果是这个的原因也不难理解,编译器在选择模板来编译时,一定回去选择最合适的模板来匹配编译!
1.3.2 偏特化
偏特化:任何针对模版参数进一步进行条件限制设计的特化版本。
其有两种表现方式:一种是将模板参数类表中的一部分参数特化(见第一个偏特化例子),另一种是针对模板参数更进一步的条件限制所设计出来的一个特化版本。
template<class t1,class t2>
class rens
{
public:rens() { cout << "rens<t1,t2>" << endl; }
private:t1 _d1;t2 _d2;
};
//偏特化,将模板参数类表中的一部分参数特化
template<class T1>
class rens<T1, int>
{
public:rens(){cout << "rens<T1,int>" << endl;}
//这个东西写不写都行
private:T1 _d1;int _d2;
};
//两个参数偏特化为指针类型
template<class T1,class T2>
class rens<T1*, T2*>
{
public:rens() { cout << "rens<T1*, T2*>" << endl; }
};
//两个参数偏特化为引用类型
template<class T1,class T2>
class rens<T1&, T2&>
{
public:rens() { cout << "rens<T1&, T2&>" << endl; }
};
//两个参数偏特化为指针类型和引用类型
template<class T1, class T2>
class rens<T1*, T2&>
{
public:rens() { cout << "rens<T1*,T2&>" << endl; }
};
int main()
{rens<double, int> r1;rens<int, double> r2;rens<int*, int*> r3;rens<int&, int&>r4;rens<int*, int&>r5;return 0;
}
运行结果:
2.模板分离编译
与普通函数不同,带有模板参数的函数的声明和定义不能分开!否则会报错!!
为此,我们的解决方案是将带模板参数的函数的声明的定义都放在.h文件中,如下图所示:
3.应用
比如我现在有一个vector容器,现在我们想写一个函数来打印它,那应该怎么办呢?我们有如下几种方式:
一、老老实实的写打印函数
#include<vector>
#include<list>void print(const vector<int>& v)
{vector<int>::const_iterator it = v.begin(); //参数是const vector<int>,所以我们的迭代 器也要用const_iteratorwhile (it != v.end()){cout << *it << " " ;++it;}cout << endl;
}
int main()
{vector<int> v1 = { 1,2,3,4,5,6 };print(v1);return 0;
}
这样写优缺点也很明确,优点是这种写法很简单,看过几遍就会写,缺点是过于死板,如果再让你打印一下double类型或者其他类型,你还得辛辛苦苦去写,太浪费时间,(不过可以适用于摸鱼哈,开玩笑请勿当真!) 为此,我们可以在函数里面加一丢丢模板,这样我们就不必在写double的打印函数了!
二、加模板参数的打印函数
#include<vector>
template <class T>
void print(const vector<T>& v)
{
// typename vector<T>::const_iterator it = v.begin(); //解释一下这里为什么要加上typename:// 因为vector<T>是一个模板类,// 编译器可能无法自动推断出vector<T>::const_iterator是一个类型,// 因此需要typename明确指出auto it = v.begin(); //推荐用auto,让编译器自动给我们推导类型while (it != v.end()){cout << *it << " ";++it;}cout << endl;
}
int main()
{vector<int> v1 = { 1,2,3,4,5,6 };print(v1);vector<double> v2 = { 2.2,5.6,9.6,8.3,4.5 };print(v2);return 0;
}
这里有两种方法,一个是用typename关键字,另外一个就是引入c++11的auto类型, 使用auto更加便捷和简洁!
现在,你已经可以打印各种类型的vector了,但是,倘若现在突然让你打印list容器呢?而且我们来不及挨个写了,为此我们再改造一下,使之得以实现!
三、设置一个容器模板
#include<vector>
#include<list>
template<class container>
void print(const container& con)
{//typename container::const_iterator it = con.begin();auto it = con.begin();while (it != con.end()){cout << *it << " ";++it;}cout << endl;
}int main()
{vector<int> v1 = { 1,2,3,4,5,6 };print(v1);vector<double> v2 = { 2.2,5.6,9.6,8.3,4.5 };print(v2);list<int> l1 = { 1,5,6,9,8,7 };print(l1);list<double> l2 = { 1.1,2.2,3.3 };print(l2);return 0;
}
这样,不论我是vector<int>,还是list<double>,我都可以通过container模板将其替代回去,完成打印的操作!
4. 模板总结
【优点】
1. 模板复用了代码,节省资源,更快的迭代开发,C++的标准模板库(STL)因此而产生
2. 增强了代码的灵活性
【缺陷】
1. 模板会导致代码膨胀问题,也会导致编译时间变长
2. 出现模板编译错误时,错误信息非常凌乱,不易定位错误
相关文章:

c++之模板进阶
在前面的文章中,我们已经简单的了解了模板的使用,在这篇文章中,我们将继续深入探讨模板 1.模板的特化 1.1 概念 通常情况下,使用模板可以实现一些与类型无关的代码,但对于一些特殊类型的可能会得到一些错误的结果&a…...

关于Internet Download Manager(IDM)强制下载合并相关二次开发
目录 前言 强制下载视频 强制合并 迁移下载列表 免责声明 附录 前言 那个下载工具IDM不说了,确实有很多便捷的功能,不过也有一些限制 常见的包括但不限于: 1.无法下载有版权保护的视频(不管真假) 2.有时候下载…...

鸿蒙HarmonyOS Next 视频边播放边缓存- OhosVideoCache
OhosVideoCache 是一个专为OpenHarmony开发(HarmonyOS也可以用)的音视频缓存库,旨在帮助开发者轻松实现音视频的边播放边缓存功能。以下是关于 OhosVideoCache 的详细介绍: 1. 核心功能 边播放边缓存:将音视频URL传递给 OhosVideoCache 处理后…...

(10) 如何获取 linux 系统上的 TCP 、 UDP 套接字的收发缓存的默认大小,以及代码范例
(1) 先介绍下后面的代码里要用到的基础函数: 以及: (2) 接着给出现代版的 读写 socket 参数的系统函数 : 以及: (3) 给出 一言的 范例代码,获取…...

程序代码篇---项目目录结构HSV掩膜Opencv图像处理
文章目录 前言第一部分:项目目录结构第二部分:HSV提取HSV色调(Hue)含义取值范围 饱和度(Saturation)含义取值范围 亮度(Value)含义取值范围 第三部分:Opencv图像处理1. 读…...

注解与反射基础
注解 概述 注解(Annotation),从jdk5.0引入。 作用 不是程序本身,可以对程序作出解释(这一点和注释没什么区别)可以被其他程序读取 格式 注释是以“注释名”在代码中存在的,还可以添加一些…...

Vue指令v-html
目录 一、Vue中的v-html指令是什么?二、v-html指令与v-text指令的区别? 一、Vue中的v-html指令是什么? v-html指令的作用是:设置元素的innerHTML,内容中有html结构会被解析为标签。 二、v-html指令与v-text指令的区别…...

院校联合以项目驱动联合培养医工计算机AI人才路径探析
一、引言 1.1 研究背景与意义 在科技飞速发展的当下,医疗人工智能作为一个极具潜力的新兴领域,正深刻地改变着传统医疗模式。从疾病的早期诊断、个性化治疗方案的制定,到药物研发的加速,人工智能技术的应用极大地提升了医疗服务…...

CDDIS从2025年2月开始数据迁移
CDDIS 将从 2025 年 2 月开始将我们的网站从 cddis.nasa.gov 迁移到 earthdata.nasa.gov,并于 2025 年 6 月结束。 期间可能对GAMIT联网数据下载造成影响。...

前端 | JavaScript中的reduce方法
1. 什么是reduce reduce 方法是 JavaScript 中数组的重要方法之一,用于对数组中的元素进行累积计算。它接收一个回调函数作为参数,并返回一个最终计算结果。reduce 在许多场景下都非常有用,比如求和、数组扁平化、对象计数、数据转换等。 2…...

【C++】B2124 判断字符串是否为回文
博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 💯前言💯题目描述输入格式:输出格式:样例: 💯方法一:我的第一种做法思路代码实现解析 💯方法二:我…...

人工智能学习(五)之机器学习逻辑回归算法
深入剖析机器学习逻辑回归算法 一、引言 在机器学习领域,逻辑回归是一种极为经典且应用广泛的算法。虽说名字里带有 “回归”,但它主要用于解决分类问题,在医学、金融、互联网等多个领域都发挥着关键作用。例如,在医学上辅助判断…...

Bash 基础与进阶实践指南
目录 Bash 简介与基础基本命令与文件操作权限管理与用户管理重定向与管道变量与环境变量通配符与正则表达式Shell 脚本结构与控制流常用内建命令与技巧文本处理常用命令作业控制与进程管理别名与函数实用技巧与注意事项更多 Bash 进阶话题参考资源 1. Bash 简介与基础 1.1 什…...

基于开源AI智能名片2 + 1链动模式S2B2C商城小程序视角下的个人IP人设构建研究
摘要:本文深入探讨在开源AI智能名片2 1链动模式S2B2C商城小程序的应用场景下,个人IP人设构建的理论与实践。通过剖析个人IP人设定义中的“诉求”“特质”“可感知”三要素,结合该小程序特点,阐述其对个人IP打造的影响与推动作用&…...

基于springboot+vue的航空散货调度系统
开发语言:Java框架:springbootJDK版本:JDK1.8服务器:tomcat7数据库:mysql 5.7(一定要5.7版本)数据库工具:Navicat11开发软件:eclipse/myeclipse/ideaMaven包:…...

【C++】B2122 单词翻转
博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 💯前言💯题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 💯一、我的做法代码实现:代码解析思路分析 💯二、老师的第一种做法代码实现&a…...

OSCP 渗透测试:网络抓包工具的使用指南
在 OSCP 考试和渗透测试中,网络数据分析是至关重要的技能。无论是嗅探明文密码、分析恶意流量,还是溯源攻击,抓包工具都是我们的得力助手。 本文将介绍 OSI 七层网络模型 及其在网络分析中的作用,并详细讲解 Wireshark 和 tcpdum…...

Android 进程间通信
什么是IPC? Android 进程间通信(IPC,Inter-Process Communication)是Android操作系统中不同进程间交换数据和资源的一种机制。由于Android是多任务操作系统,每个应用通常运行在自己的进程中,以提高安全性和…...

Kubernetes学习之通过Service访问Pod
一、基础概述 1.当通过deployment等controller动态创建和销毁pod使得每个pod都有自己的ip地址,当controller用新的pod替代发生故障的pod时,新的pod会分配到新的ip地址,那么客户端如何稳定的找到并访问pod提供的服务。 2.创建service service从…...

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】2.18 对象数组:在NumPy中存储Python对象
2.18 对象数组:在NumPy中存储Python对象 目录 #mermaid-svg-shERrGOBuM2rBzeB {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-shERrGOBuM2rBzeB .error-icon{fill:#552222;}#mermaid-svg-shERrGOBuM2rB…...

Web - CSS3基础语法与盒模型
概述 这篇文章是关于 Web 前端 CSS3 的基础语法与盒模型的讲解。包括 CSS3 层叠性及处理冲突规则、伪元素和新增伪类元素、属性选择器等。还介绍了文本与字体属性,如段落和行相关属性、字体文本属性。最后阐述了盒子模型,如元素隐藏、行内与块元素转换、…...

CSS知识总结
CSS(层叠样式表,Cascading Style Sheets)是一种用于描述网页内容视觉表现的样式语言,与HTML(结构)和JavaScript(行为)共同构成现代Web开发的三大核心技术。 一、基本概念 定义&…...

基于Spring Security 6的OAuth2 系列之十 - 授权服务器--刷新token
之所以想写这一系列,是因为之前工作过程中使用Spring Security OAuth2搭建了网关和授权服务器,但当时基于spring-boot 2.3.x,其默认的Spring Security是5.3.x。之后新项目升级到了spring-boot 3.3.0,结果一看Spring Security也升级…...

信息学奥赛一本通 2113:【24CSPJ普及组】小木棍(sticks) | 洛谷 P11229 [CSP-J 2024] 小木棍
【题目链接】 ybt 2113:【24CSPJ普及组】小木棍(sticks) 洛谷 P11229 [CSP-J 2024] 小木棍 【题目考点】 1. 思维题,找规律 【解题思路】 解法1:找规律 该题为:求n根木棍组成的无前导0的所有可能的数…...

安装hami的笔记
k3s环境下安装hami提示如下错误: "failed to “StartContainer” for “kube-scheduler” with InvalidImageName: "Failed to apply default image tag “registry.cn-hangzhou.aliyuncs.com/google_containers/kube-scheduler:v1.31.2k3s1”: 没有Inva…...

【区块链】区块链密码学基础
🌈个人主页: 鑫宝Code 🔥热门专栏: 闲话杂谈| 炫酷HTML | JavaScript基础 💫个人格言: "如无必要,勿增实体" 文章目录 区块链密码学基础引言一、哈希函数1.1 基本概念1.2 数学表达 二、非对称加密2.1…...

强化学习笔记(5)——PPO
PPO视频课程来源 首先理解采样期望的转换 变量x在p(x)分布下,函数f(x)的期望 等于f(x)乘以对应出现概率p(x)的累加 经过转换后变成 x在q(x)分布下,f(x)*p(x)/q(x) 的期望。 起因是:求最大化回报的期望,所以对ceta求梯度 具体举例…...

【C语言入门】解锁核心关键字的终极奥秘与实战应用(三)
目录 一、auto 1.1. 作用 1.2. 特性 1.3. 代码示例 二、register 2.1. 作用 2.2. 特性 2.3. 代码示例 三、static 3.1. 修饰局部变量 3.2. 修饰全局变量 3.3. 修饰函数 四、extern 4.1. 作用 4.2. 特性 4.3. 代码示例 五、volatile 5.1. 作用 5.2. 代码示例…...

寒假day10
第十天:请写出以下几个数据的类型 整数 a int a的地址 int* 存放a的数组b …...

本地部署与使用SenseVoice语音大模型简析
前言 SenseVoice 是一种语音基础模型,具有多种语音理解功能,包括自动语音识别 (ASR)、口语识别 (LID)、语音情感识别 (SER) 和音频事件检测 (AED)。本博客将指导您安装和使用 SenseVoice 模型,使其尽可能方便用户使用。 Github 仓库链接: ht…...