【C++】模板详细讲解(含反向迭代器)
欢迎来到我的Blog,点击关注哦💕
前言:
C++的模板在是泛型编程的重要组成部分,编写在不同类型上工作的代码,而无需为每个类型编写重复的代码,这有助于减少代码冗余并提高代码的可维护性。
模板
模板的介绍
- C++模板是一种强大的编程技术,它允许程序员编写与类型无关的代码,即泛型编程。
- 模板可以用于定义泛型函数和类,这些函数和类可以在编译时根据实际使用的数据类型进行实例化。
- 模板的使用提高了代码的复用性和灵活性,减少了冗余代码的编写
模板分类
函数模板
函数模板的定义通常包含以下几个部分:
- template关键字:表示接下来的声明是一个模板。
- 模板参数列表:位于尖括号
<>中,可以包含类型参数和非类型参数。 - 函数声明和定义:与普通函数类似,但使用模板参数列表中的类型来定义函数。
#include <iostream>
//函数模板
template <typename T>
T add(T a, T b) {return a + b;
}int main() {int x = 10, y = 20;double d1 = 1.5, d2 = 2.5;std::cout << "Adding two integers: " << add(x, y) << std::endl;std::cout << "Adding two doubles: " << add(d1, d2) << std::endl;return 0;
}
类模板
类模板的定义与函数模板类似,但用于定义类结构。以下是一个简单的类模板示例:
#include <iostream>template <typename T>
class SimpleContainer {
private:T data;public:SimpleContainer(T value) : data(value) {}T getData() const { return data; }void setData(T value) { data = value; }
};int main() {SimpleContainer<int> intContainer(10);std::cout << "Integer data: " << intContainer.getData() << std::endl;SimpleContainer<double> doubleContainer(3.14);std::cout << "Double data: " << doubleContainer.getData() << std::endl;return 0;
}
在这个例子中,SimpleContainer是一个类模板,它可以用于任何数据类型T。当在main函数中创建SimpleContainer的实例时,编译器会根据提供的类型参数自动生成相应的类实例。
类模板的成员函数
类模板的成员函数可以是模板函数,也可以是普通函数。模板成员函数在类模板的定义中直接声明,而普通成员函数可以在类模板外定义,此时需要显式指定模板参数。
template <typename T>
class MyClass {
public:void templateFunction(T value);void normalFunction();
};template <typename T>
void MyClass<T>::templateFunction(T value) {// Template member function
}template <typename T>
void MyClass<T>::normalFunction() {// Non-template member function, defined outside the class
}
函数模板实例化
函数模板的实例化通常发生在函数被调用时。编译器会根据传递给函数模板的参数类型,自动实例化一个特定类型的函数。例如:
template <typename T>
void print(T value) {std::cout << value << std::endl;
}int main() {print(10); // 实例化为 void print(int)print(3.14); // 实例化为 void print(double)
}
在这个例子中,print函数模板被两次调用,分别传入了int和double类型的参数,因此编译器会为每种类型生成一个具体的函数实例。
类模板实例化
类模板的实例化发生在创建类模板的实例时,或者当类模板的成员函数被调用时。例如:
template <typename T>
class Box {
public:T value;Box(T v) : value(v) {}
};int main() {Box<int> intBox(10); // 实例化为 class Box<int>Box<double> dblBox(3.14); // 实例化为 class Box<double>
}
这里,Box类模板被用于创建两个不同类型的实例,Box<int>和Box<double>。
隐式实例化与显式实例化
- 隐式实例化:当模板被调用或使用时,编译器自动进行实例化。这是最常见的情况,如上述例子所示。
- 显式实例化:在某些情况下,可能需要在编译器之外显式地实例化模板。这通常用于控制模板实例的生成,避免不必要的实例化,或者在编译时提前生成一些模板实例以提高运行时性能。显式实例化的语法如下:
template class Box<int>; // 显式实例化 Box<int>
非类型模板参数
- 非类型模板参数是C++模板中的一种机制,它允许模板在编译时期使用常量值作为参数。
template<class T ,size_t N = 10>
class sulotion
{
public:sulotion(const T& x) {_a[1] = 10;}void print(){for (int i = 0; i < 10; i++){cout << _a[i]<<" ";}cout << endl;}
private:T _a[N];
};
模板的特化
C++模板特化是一种技术,允许开发者为特定类型或类型模式提供不同的模板实现,以覆盖通用模板的默认行为。
- 必须要先有一个基础的函数模板
- 关键字template后面接一对空的尖括号<>
- 函数名后跟一对尖括号,尖括号中指定需要特化的类型
- 函数形参表: 必须要和模板函数的基础参数类型完全相同,如果不同编译器可能会报一些奇怪的错误。
全特化
- 全特化是指为某个特定的模板参数提供专门的实现,通常用于处理某个特定类型的特殊情况。
- 在全特化中,模板参数列表中的所有参数都被确定化,形成一个完全具体化的模板版本。
template<class T1, class T2>
class sulotion
{
public:sulotion(const T1& x, const T2& y): _data1(x),_data2(y){}void print(){cout << _data1 << " " << _data2 << endl;}
private:T1 _data1 ;T2 _data2 ;
};
//特化
template<>
class sulotion<int,char>
{
public:sulotion(const int& x, const char& y): _data1(x), _data2(y){}void print(){cout << _data1 << " " << _data2 << endl;}
private:int _data1;char _data2;
};
偏特化
- 偏特化是指为一组模板参数提供专门的实现,而不是针对单个特定的参数。
- 偏特化允许更细粒度的控制和更广泛的特化。类模板可以进行偏特化,但函数模板不支持偏特化,因为编译器无法区分不同的偏特化版本。
- 在偏特化中,只有部分模板参数被确定化,而其他参数保持泛型。
template<class T1, class T2>
class sulotion
{
public:sulotion(const T1& x, const T2& y): _data1(x),_data2(y){}void print(){cout << _data1 << " " << _data2 << endl;}
private:T1 _data1 ;T2 _data2 ;
};
//偏特化
template<class T1>
class sulotion<T1,char>
{
public:sulotion(const T1& x, const char& y): _data1(x), _data2(y){}void print(){cout << _data1 << " " << _data2 << endl;}
private:T1 _data1;char _data2;
};
模板的分离编译
- C++模板的分离编译是指将模板的声明和定义分离开来,以适应大型项目中模块化的开发需求。
- 传统上,类模板的声明和定义通常放在同一个头文件中,但这种做法可能导致编译速度慢和编译依赖管理复杂。
- 分离编译允许开发者将模板的声明放在头文件中,而将定义放在源文件中,这样可以减少头文件的大小,加速编译过程,并减少不必要的编译依赖。
模板分离的编译容易链接错误
解决方法:
- 将声明和定义放在同一个头文件中:这是最直接的方法,可以确保模板的声明和定义在编译时可见,从而避免链接错误。
- 显示实例化:通过在源文件中显式实例化模板,告诉编译器为特定类型生成模板实例。这种方法虽然可以解决链接错误,但会降低代码的泛化能力,因为每次使用新类型时都需要更新实例化代码。
C++对模板的应用
- 容器(Containers):提供了多种数据结构的实现,如
vector、list、deque等,这些容器通过模板类来支持不同数据类型的存储和管理。 - 迭代器(Iterators):定义了一组接口,用于遍历容器中的元素。迭代器本身也是模板类,它们抽象了对容器元素的访问方式,使得算法能够独立于具体的数据结构实现。
- 算法(Algorithms):提供了一系列的函数模板,用于执行常见的数据操作,如排序、搜索、复制等。这些算法通过模板定义,可以广泛应用于不同类型的容器。
- 函数对象(Functors):也称为仿函数,是重载了
operator()的对象,可以作为算法的参数,提供自定义的操作逻辑。函数对象同样是基于模板实现的,以支持不同类型的操作。 - 适配器(Adapters):用于修改或包装现有容器或迭代器的接口,以满足特定的使用需求。适配器也是基于模板技术实现的,提供了灵活的扩展机制
C++反向迭代器
- C++的反向迭代器是对正向迭代器的再次封装。
正向迭代器
//迭代器
template<class T,class Ref,class ptr>struct _list_iterator{typedef _list_node<T> Node;typedef _list_iterator<T, Ref,ptr> self;Node* _node;_list_iterator (Node* node):_node(node){}//重载operator*Ref& operator* (){return _node->_val;}//重载operator->ptr operator->(){return _node->_val;}//重载operator++(前置)self& operator++(){_node = _node->_next;return *this;}//重载operator++(后置)self& operator++(int){self tmp(*this);_node = _node->_next;return tmp;}//重载operator--(前置)self& operator--(){_node = _node->_prev;return *this;}//重载operator--(后置)self& operator--(int){self tmp(*this);_node = _node->_prev;return tmp;}//重载operator!=bool operator!=(const self& it)const {return _node != it._node;}//重载operator==bool operator==(const self& it)const{return _node == it._node;}};
反向迭代器
-
iterator和reverse_itrator是成为镜像对称 -
operartor*是解引用前一个数据,也就是迭代器的end -
++就是调用正向的–,反正 – 就是++
template<class iterator ,class Ref,class Ptr>struct Reverse_Iterator{typedef Reverse_Iterator<iterator, Ref, Ptr> self;iterator _it;Reverse_Iterator(iterator it):_it(it){}Ref operator* (){iterator tmp(_it);return *(--tmp);}Ptr operator->(){return &(operator* ());}self& operator++(){--_it;return *this;}self& operator--(){++_it;return *this;}bool operator==(const self& s)const{return _it == s._it;}bool operator!=(const self& s)const{return _it != s._it;}};
相关文章:
【C++】模板详细讲解(含反向迭代器)
欢迎来到我的Blog,点击关注哦💕 前言: C的模板在是泛型编程的重要组成部分,编写在不同类型上工作的代码,而无需为每个类型编写重复的代码,这有助于减少代码冗余并提高代码的可维护性。 模板 模板的介绍 …...
haproxy七层代理详解之-完整安装部署流程及负载均衡实现-及热更新方法
一.负载均衡 1.1负载均衡时什么 负载均衡:Load Balance,简称LB,是一种服务或基于硬件设备等实现的高可用反向代理技术,负载均网络流量等)分担给指定的一个或多个后端特定的服务器或设备,从而提高了衡将特定的业务(web服务、公司…...
C++11 bind
bind bind 用来将可调用对象和参数一起进行绑定。可调用对象包括普通函数、全局函 数、静态函数、类静态函数甚至是类成员函数,参数包括普通参数和类成员。绑定后的 结果,可以使用 std::function 进行保存,并延迟调用到我们需要的时候。 绑…...
LeetCode199 二叉树的右视图
前言 题目: 199. 二叉树的右视图 文档: 代码随想录——二叉树的右视图 编程语言: C 解题状态: 成功解决! 思路 二叉树层序遍历问题的变种,右视图即意味着二叉树每层的最后一个节点。 代码 /*** Definiti…...
数据赋能(172)——开发:数据挖掘——影响因素、直接作用、主要特征
影响因素 主要影响因素如下: 数据类型与属性: 数据类型和对象的不同属性会使用不同的数据类型来描述,如年龄可能是整数类型,而生日则是日期类型。数据挖掘时需要对不同的数据类型进行不同的处理,这直接影响到挖掘算法…...
Vue:Vue3-TypeScript-Pinia-Vite-pnpm / 基础项目 / 20240807
一、项目技术栈 / 依赖 序号技术栈版本解释1node20.14.02vue 3.4.31 3vite 5.3.4 4TypeScript 5.2.2 5 types/node 22.0.2 解决TypeScript项目中缺少对应模块的类型定义文件的问题6 element-plus 2.7.8 ui组建7 types/js-cookie js-cookie 3.0.6 3.0.5 8 sass 1.77.8 9 hu…...
windows Qt 录屏 录音
启动录屏录音: connect(&m_Process, &QProcess::readyReadStandardOutput, [&]() {qDebug() << "Standard output:" << QString::fromLocal8Bit(m_Process.readAllStandardOutput()); });connect(&m_Process, &QProcess…...
AAC中的ADTS格式分析
😎 作者介绍:欢迎来到我的主页👈,我是程序员行者孙,一个热爱分享技术的制能工人。计算机本硕,人工制能研究生。公众号:AI Sun(领取大厂面经等资料),欢迎加我的…...
iOS内存管理---MRC vs ARC
系列文章目录 iOS基础—Block iOS基础—Protocol iOS基础—KVC vs KVO iOS网络—AFNetworking iOS网络—NSURLSession iOS内存管理—MRC vs ARC iOS基础—Category vs Extension iOS基础—多线程:GCD、NSThread、NSOperation iOS基础—常用三方库:Mason…...
【数学分析笔记】第1章第1节:集合(2)
这节我自己补了一些内容,要不然听不太懂陈纪修老师讲的 1. 集合与映射 1.3 子集与真子集 假如有 S \textbf{S} S和 T \textbf{T} T两个集合,其中, S \textbf{S} S的所有元素都属于 T \textbf{T} T,则称 S \textbf{S} S是 T \te…...
大话设计模式:七大设计原则
目录 一、单一职责原则(Single Responsibility Principle, SRP) 二、开放封闭原则(Open-Closed Principle, OCP) 三、依赖倒置原则(Dependency Inversion Principle, DIP) 四、里氏替换原则&am…...
利用多商家AI智能名片小程序提升消费者参与度与个性化体验:重塑零售行业的忠诚策略
摘要:在数字化浪潮席卷全球的今天,零售行业正经历着前所未有的变革。消费者对于购物体验的需求日益多样化、个性化,而零售商则面临着如何将一次性购物者转化为品牌忠诚者的巨大挑战。多商家AI智能名片小程序作为一种新兴的数字营销工具&#…...
Scala 闭包
Scala 闭包 Scala 闭包是一个非常重要的概念,它允许我们创建可以在稍后某个时间点执行的功能片段。闭包是一个函数,它捕获了封闭范围内的变量,即使在函数外部,这些变量也可以在函数内部使用。这使得闭包成为处理异步操作、回调和…...
前端JS总结(中)
目录 前言 正文 对象: 分类: 自定义对象: 内置对象: 重点: 常用内置对象: 字符串对象:String 获取字符串长度: 大小写转换: 获取某个字符: 截取字…...
elasticsearch的match_phrase匹配及其可能导致的查询问题
目录 1.match_phrase使用介绍 2.规避可能产生的查询问题 解决方式 一.查询和索引分词器一致,即都使用max_word或者都使用smart 二.使用slop增加匹配的容忍度 3.参考文档 1.match_phrase使用介绍 elasticsearch的match_phrase查询是全文查询,主要用…...
C++快速理解之继承
一、继承和派生 1.是什么? C 中的继承是类与类之间的关系,与现实世界中的继承类似 例如:儿子继承父亲的财产 继承(Inheritance)可以理解为一个类从另一个类获取成员变量和成员函数的过程 例如: 类B继承…...
Node.JS - 基础(Express)
目录 A. 简介 B. 下载,安装 C. 启动服务,查看文件结构 A. 简介 Express 是一个基于 Node.js 平台的极简、灵活的 Web 应用开发框架,它提供了一系列强大的功能来构建 Web 应用程序和 API。 一、Express 的基本特点 简洁的路由系统: Express 的路由系…...
I/O复用
I/O复用使得程序能够同时监听多个文件描述符,这对提高程序的性能至关重要。 举个例子: 就好比你天天玩手机,你妈为了监控你,在你房间安装了一个监控,这个监控可以实时监控你的一举一动,并上传到你妈手机上…...
【验证可用】解决安装SQL Server数据库时,报错“启用 windows 功能 NetFx3 时出错,错误代码:-2146498298......“的问题
目录 背景一. 报错信息1.1 报错的图片信息1.2 报错的文字信息 二. 解决报错2.1 下载 NetFx3.cab 文件2.2 执行命令 三. SQL Server 修复安装 背景 一次在阿里云服务器安装 SQL Server 2012时,系统报错了,导致安装进行不下去…通过在网上查找了多种解决方…...
STM32的SDIO接口详解
目录 1. 定义与兼容性 2. SDIO时钟 3. SDIO命令与响应 4. SDIO块数据传输 5. SDIO控制器的硬件结构 6.代码实现 1.SD初始化 2.测试SD卡的读取 3.测试SD卡的写入 STM32的SDIO(Secure Digital Input/Output,安全数字输入输出)接口是一…...
Python|GIF 解析与构建(5):手搓截屏和帧率控制
目录 Python|GIF 解析与构建(5):手搓截屏和帧率控制 一、引言 二、技术实现:手搓截屏模块 2.1 核心原理 2.2 代码解析:ScreenshotData类 2.2.1 截图函数:capture_screen 三、技术实现&…...
多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验
一、多模态商品数据接口的技术架构 (一)多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如,当用户上传一张“蓝色连衣裙”的图片时,接口可自动提取图像中的颜色(RGB值&…...
微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...
ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...
用docker来安装部署freeswitch记录
今天刚才测试一个callcenter的项目,所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...
实现弹窗随键盘上移居中
实现弹窗随键盘上移的核心思路 在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...
tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...
【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南
1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发,使用DevEco Studio作为开发工具,采用Java语言实现,包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...
