当前位置: 首页 > news >正文

自己的类支持基于范围的for循环 (深入探索)

自己的类支持基于范围的for循环 (深入探索)

编译器实际运行伪代码为:

auto && __range = range_expression;
auto __begin = begin_expr;
auto __end = end_expr;
for (; __begin != __end; ++__begin) {range_declaration = *__begin;loop_statement
}

观察伪代码,关于迭代器用到的运算符,用到了 * , != 和 前置++

所以我们需要对迭代器实现以下的内容

  1. *
  2. !=
  3. ++ (prefix++)

然后根据c++标准(编译器)规定,我们还需要对对应的类实现begin和end函数,返回对应的迭代器

实现

迭代器类的实现
template <typename _Iterator>
class MyIterator {protected:_Iterator _M_current;typedef std::iterator_traits<_Iterator> __traits_type;// just use std::iterator_traits to trait the typespublic:typedef _Iterator iterator_type;typedef typename __traits_type::iterator_category iterator_category;typedef typename __traits_type::value_type value_type;typedef typename __traits_type::difference_type difference_type;typedef typename __traits_type::reference reference;typedef typename __traits_type::pointer pointer;public:MyIterator() noexcept : _M_current(_Iterator()) {}explicit MyIterator(const _Iterator& __i) noexcept : _M_current(__i) {}reference operator*() const noexcept { return *_M_current; }MyIterator& operator++() noexcept {++_M_current;return *this;}// not need base function. Just to expose _M_currentconst _Iterator& base() const noexcept { return _M_current; }
};// deal with different types of left and right != operators
template <typename _IteratorL, typename _IteratorR>
[[__nodiscard__]] inline bool operator!=(const MyIterator<_IteratorL>& __lhs,const MyIterator<_IteratorR>& __rhs) noexcept {return __lhs.base() != __rhs.base();
}// deal with same types of left and right != operators
template <typename _Iterator>
[[__nodiscard__]] inline bool operator!=(const MyIterator<_Iterator>& __lhs,const MyIterator<_Iterator>& __rhs) noexcept {return __lhs.base() != __rhs.base();
}

需要💡几点:

  • 这里的const都不是乱加的,都是有讲究的
  • 这里用到了标准库的迭代器类型萃取,没啥难度,但是对应特化版本写起来很麻烦,我这就不重新写了,理解上也很简单
  • 这里写了一个base函数,不是强制要求的,在这里也只是为了暴露指针,让全局的重载!=可以访问到,当然把指针设成public也可以
  • 重载的!=有两个版本,分别对应!=左右类型是否一致的情况

类的begin和end实现

实际上,我们只需要把下面这段代码插入到我们要的类里就可以了


/*
* And the data class must impl begin and end function
* to return the correspond iterator
* */
using iterator = MyIterator<T*>;
using const_iterator = MyIterator<const T*>;public:
iterator begin() { return iterator(str); }
iterator end() { return iterator(str + N); }
const_iterator begin() const { return const_iterator(str); }
const_iterator end() const { return const_iterator(str + N); }

这里的str和N换成你对应要的内容

当然这里只针对顺序容器,如果是其它类型,会复杂一点,迭代器也需要重新设计,就需要第二个参数了

标准库中普通顺序容器模板也是有两个,但是因为顺序可以直接对指针进行++,第二个用处不大,我这里也就直接省略了

示例

我这里给了一个最基本的使用demo示例,仅供参考:

template <typename T, size_t N>
class Test {public:Test() = default;Test(std::initializer_list<T> obj) {T* cur = str;for (const auto& val : obj) {*cur = val;++cur;}}T* data() {return str;}const T* data() const { return str; }/** And the data class must impl begin and end function* to return the correspond iterator* */using iterator = MyIterator<T*>;using const_iterator = MyIterator<const T*>;public:iterator begin() { return iterator(str); }iterator end() { return iterator(str + N); }const_iterator begin() const { return const_iterator(str); }const_iterator end() const { return const_iterator(str + N); }private:T str[N]{};public:friend std::ostream& operator<<(std::ostream& os, const Test& obj) {for (const auto& val : obj) {os << val << " ";}return os;}
};

使用示例:

  {Test<int, 10> test;for (auto& val : test) {static int i = 0;val = ++i;}std::cout << test << std::endl;}{const Test<int, 10> test{12, 34, 56, 78, 910};for (const auto& val : test) {std::cout << val << " ";}std::cout << std::endl;}

输出:

12 45 123 12 0 0 0 0 0 0  
1 2 3 4 5 6 7 8 9 10 
12 34 56 78 910 0 0 0 0 0 

小问题:如果一个类代码已经写好了,我们没法插入自己的begin函数和end函数怎么办

那么c++编译器在看你这个类如果没有begin和end函数,就回去查找全局的begin和end

那么全局的begin和end应该怎么写呢?

我是这么实现的,也顺利通过了,左右值/const也都走了对应版本

template <typename T, size_t N>
auto begin(Test<T, N>& a) {return MyIterator<T*>(a.data());
}
template <typename T, size_t N>
auto end(Test<T, N>& a) {return MyIterator<T*>(a.data() + N);
}
template <typename T, size_t N>
auto begin(const Test<T, N>& a) {return MyIterator<const T*>(a.data());
}
template <typename T, size_t N>
auto end(const Test<T, N>& a) {return MyIterator<const T*>(a.data() + N);
}

但怎么说呢,我觉得应该有更优雅的写法或者规范,但是这一块没有参考

不像前面写迭代器可以看标准库,保证不出错,但是这个标准库里肯定也没有示例,就不好说了

如果有谁看到有官方示例或推荐,欢迎来联系我

相关文章:

自己的类支持基于范围的for循环 (深入探索)

自己的类支持基于范围的for循环 (深入探索) 编译器实际运行伪代码为: auto && __range range_expression; auto __begin begin_expr; auto __end end_expr; for (; __begin ! __end; __begin) {range_declaration *__begin;loop_statement }观察伪代码&#xff0…...

Multi Scale Supervised 3D U-Net for Kidney and Tumor Segmentation

目录 摘要1 引言2 方法2.1 预处理和数据增强2.2 网络的体系结构2.3 训练过程2.4 推理与后处理 3 实验与结果4 结论与讨论 摘要 U-Net在各种医学图像分割挑战中取得了巨大成功。一些新的、带有花里胡哨功能的架构可能在某些数据集中在使用最佳超参数时取得成功&#xff0c;但它们…...

《操作系统真象还原》第一章 部署工作环境

ref&#xff1a;https://www.bilibili.com/video/BV1kg4y1V7TV/?spm_id_from333.999.0.0&vd_source3f7ae4b9d3a2d84bf24ff25f3294d107 https://www.bilibili.com/video/BV1SQ4y1A7ZE/?spm_id_from333.337.search-card.all.click&vd_source3f7ae4b9d3a2d84bf24ff25f32…...

SpringCloud-Config

一、介绍 &#xff08;1&#xff09;服务注册中心 &#xff08;2&#xff09;管理各个服务上的application.yml&#xff0c;支持动态修改&#xff0c;但不会影响客户端配置 &#xff08;3&#xff09;一般将application.yml文件放在git上&#xff0c;客户端通过http/https方式…...

劣币驱良币的 pacing 之殇

都说 pacing 好 burst 孬(参见&#xff1a;为啥 pacing)&#xff0c;就像都知道金币好&#xff0c;掺铁金币孬一样。可现实中掺铁的金币流通性却更好&#xff0c;劣币驱良币。劣币流通性好在卖方希望收到别人的良币而储存&#xff0c;而自己作为买方只使用劣币。 burst 和 pac…...

Gin 中的 Session(会话控制)

Session 介绍 session和cookie实现的底层目标是一致的,但是从根本而言实现的方法是不同的; session 是另一种记录客户状态的机制, 不同的是 Cookie 保存在客户端浏览器中,而 session保存 在服务器上 ; Session 的工作流程 当客户端浏览器第一次访问服务器并发送请求时,服…...

ChatGPT AIGC 实现数据分析可视化三维空间展示效果

使用三维空间图展示数据有以下一些好处&#xff1a; 1可视化复杂性&#xff1a;三维图可以展示三个或更多的变量&#xff0c;一眼就能看出数据各维度之间的关系&#xff0c;使复杂数据的理解和分析变得更为直观。 2检测模式和趋势&#xff1a;通过三维图&#xff0c;用户可以…...

Stable Diffusion 动画animatediff-cli-prompt-travel

基于 sd-webui-animatediff 生成动画或者动态图的基础功能,animatediff-cli-prompt-travel突破了部分限制,能让视频生成的时间更长,并且能加入controlnet和提示词信息控制每个片段,并不像之前 sd-webui-animatediff 的一套关键词控制全部画面。 动图太大传不上来,凑合看每…...

fatal error C1083: 无法打开包括文件: “ta_libc.h”: No such file or directory

用python做交易数据分析时&#xff0c;可以用talib库计算各类指标&#xff0c;这个库通过以下命令安装&#xff1a; pip install TA-Lib -i https://pypi.tuna.tsinghua.edu.cn/simple windows安装时可能出现本文标题所示的错误&#xff0c;可按如下步骤解决&#xff1a; 1、去…...

c 语言基础题目:L1-034 点赞

微博上有个“点赞”功能&#xff0c;你可以为你喜欢的博文点个赞表示支持。每篇博文都有一些刻画其特性的标签&#xff0c;而你点赞的博文的类型&#xff0c;也间接刻画了你的特性。本题就要求你写个程序&#xff0c;通过统计一个人点赞的纪录&#xff0c;分析这个人的特性。 …...

SaaS人力资源管理系统的Bug

SaaS人力资源管理系统的Bug Bug1【18】 这里我是直接把代码复制过来的&#xff0c;然后就有一个空白 这是因为它的代码有问题&#xff0c;原本的代码如下所示 <el-table-column fixed type"index" label"序号" width"50"></el-table…...

GPTQ 和 AWQ:LLM 量化方法的比较

大语言模型&#xff08;LLM&#xff09;在自然语言处理&#xff08;NLP&#xff09;任务中取得了显著的进展。然而&#xff0c;LLM 通常具有非常大的模型大小和计算复杂度&#xff0c;这限制了它们在实际应用中的部署。 量化是将浮点数权重转换为低精度整数的过程&#xff0c;…...

JVM:虚拟机类加载机制

JVM:虚拟机类加载机制 什么是JVM的类加载 众所周知&#xff0c;Java是面向对象编程的一门语言&#xff0c;每一个对象都是一个类的实例。所谓类加载&#xff0c;就是JVM虚拟机把描述类的数据从class文件加载到内存&#xff0c;并对数据进行校验&#xff0c;转换解析和初始化&a…...

PHP筆記

​ 前言因緣際會下還是開始學習php了。經歷了風風雨雨終於在今年暑假要去加拿大留學了&#xff0c;php會是第二年的其中一門必修課程&#xff0c;加上最近前端也真的蠻心累&#xff0c;也許有一門精進的後端語言&#xff0c;日後轉職會有更寬廣的道路&#xff0c;對自己說加油&…...

IDEA启动报错Failed to create JVM. JVM path的解决办法

今天启动IDEA时IDEA报错&#xff0c;提示如下。 if you already hava a JDK installed, define a JAVA_HOME variable in Computer > Systen Properties > System Settings > Environment Variables.Failed to create JVM. JVM path:D:\ideaIU2023.2.3\IntelliJ IDE…...

源码解析FlinkKafkaConsumer支持周期性水位线发送

背景 当flink消费kafka的消息时&#xff0c;我们经常会用到FlinkKafkaConsumer进行水位线的发送&#xff0c;本文就从源码看下FlinkKafkaConsumer.assignTimestampsAndWatermarks指定周期性水位线发送的流程 FlinkKafkaConsumer水位线发送 1.首先从Fetcher类开始&#xff0c…...

Nginx:动静分离(示意图+配置讲解)

示意图&#xff1a; 动静分离 动静分离是指将动态内容和静态内容分开处理的一种方式。通常&#xff0c;动态内容是指由服务器端处理的&#xff0c;例如动态生成的网页、数据库查询等。静态内容是指不需要经过服务器端处理的&#xff0c;例如图片、CSS、JavaScript文件等。通过…...

通讯网关软件024——利用CommGate X2Access实现Modbus TCP数据转储Access

本文介绍利用CommGate X2ACCESS实现从Modbus TCP设备读取数据并转储至ACCESS数据库。CommGate X2ACCESS是宁波科安网信开发的网关软件&#xff0c;软件可以登录到网信智汇(http://wangxinzhihui.com)下载。 【案例】如下图所示&#xff0c;实现从Modbus TCP设备读取数据并转储…...

vim工具的使用

目录 vi/vim键盘图 1、vim的基本概念 2、vim的基本使用 3、vim命令模式命令集 4、vim底行模式命令集 5、参考资料 vi/vim键盘图 1、vim的基本概念 vi和vim的区别&#xff1a;vi和vim的区别简单点来说&#xff0c;它们都是多模式编辑器&#xff0c;不同的是vim是vi…...

Docker学习_存储篇

当以默认的方式创建容器时&#xff0c;容器中的数据无法直接和其他容器或宿主机共享。为了解决这个问题需要学习一些Docker 存储卷的知识。 Docker提供了三种存储的方式。 bind mount共享宿主机文件目录volume共享docker存储卷tmpfs mount共享内存 volume* volume方式是容器…...

微信小程序获取当前日期时间

一、直接使用方式 在小程序中获取当前系统日期和时间&#xff0c;可直接拿来使用的常用的日期格式 //1. 当前日期 YYYY-MM-DDnew Date().toISOString().substring(0, 10)new Date().toJSON().substring(0, 10)//2. 当前日期 YYYY/MM/DDnew Date().toLocaleDateString()//3.…...

Unity关键词语音识别

一、背景 最近使用unity开发语音交互内容的时候&#xff0c;遇到了这样的需求&#xff0c;就是需要使用语音关键字来唤醒应用程序&#xff0c;然后再和程序做交互&#xff0c;有点像智能音箱的意思。具体的技术方案方面&#xff0c;也找了一些第三方的服务&#xff0c;比如百度…...

SpringBoot的配置文件——.yml和.properties

目录 1. Spring Boot 配置文件的使用场景 2. 配置文件的两种格式 2.0 特殊说明&#xff1a; 2.1 .properties 2.1.1 格式 2.2.2 缺陷 2.2.3 解决中文乱码的问题 2.2 .yml 2.2.3 格式 配置数据库连接 注意转义字符 ​编辑 ​编辑 配置null 配置对象 从.yml读取文件举例 Stud…...

Retrieve Anything To Augment Large Language Models

简介 论文主要介绍了一套通过对比学习和蒸馏学习的方法&#xff0c;来增强学习了embedding向量&#xff0c;然后能够在知识增强&#xff0c;长上下文建模&#xff0c;ICL和工具学习等方面来增强大模型能力。...

什么是面向对象编程

面向对象编程&#xff08;Object-oriented programming&#xff0c;简称OOP&#xff09;是一种编程范型&#xff0c;通过将数据和方法&#xff08;即属性和行为&#xff09;组织在一个单元中&#xff0c;以模拟现实世界中的实体或概念。在面向对象编程中&#xff0c;数据和方法…...

c++视觉处理----固定阈值操作:Threshold()函数,实时处理:二值化,反二值化,截断,设为零,反向设为零

固定阈值操作&#xff1a; Threshold()函数 cv::threshold() 函数是OpenCV中用于执行固定阈值二值化操作的函数。它可以用来将图像中的像素值根据用户定义的阈值转换为二进制值&#xff08;0或255&#xff09;&#xff0c;以便进行图像分割、物体检测和特征提取等任务。 cv::…...

KWin、libdrm、DRM从上到下全过程 —— drmModeAddFBxxx(8)

接前一篇文章:KWin、libdrm、DRM从上到下全过程 —— drmModeAddFBxxx(7) 上一回讲到了drm_internal_framebuffer_create函数中的framebuffer_check函数中的drm_get_format_info函数,讲解了该函数的第一部分暨前一部分,本文讲解后一部分。为了便于理解以及理清脉络和当前所…...

【问题解决】Ubuntu 安装 SeisSol 依赖 easi 报错解决: undefined reference to `H5free_memory‘

兼职帮客户安装 SeisSol 时问题解决&#xff0c;安装 easi 这个报错卡了很久&#xff08;搞了一天&#xff09;&#xff0c;记录下&#xff0c;以备后用~ # 编译器问题 rootubuntu:/opt/easi# make -j install [ 4%] Building CXX object CMakeFiles/easi.dir/src/component/…...

循环小数(Repeating Decimals, ACM/ICPC World Finals 1990, UVa202)rust解法

输入整数a和b&#xff08;0≤a≤3000&#xff0c;1≤b≤3000&#xff09;&#xff0c;输出a/b的循环小数表示以及循环节长度。例如a5&#xff0c;b43&#xff0c;小数表示为0.(116279069767441860465)&#xff0c;循环节长度为21。 解法 就是模拟竖式除法 use std::{collecti…...

[GAMES101]透视投影变换矩阵中为什么需要改变z值

一、问题提出 在GAMES101-Lecture4 Transformation Matrices 一节中&#xff0c;闫老师介绍了正交投影和透视投影。 在讲透视投影变换矩阵 M p e r s p → o r t h o M_{persp→ortho} Mpersp→ortho​时&#xff0c;同学们对矩阵中的z分量是变化的还是不变的有很多争论。即下…...