自己的类支持基于范围的for循环 (深入探索)
自己的类支持基于范围的for循环 (深入探索)
编译器实际运行伪代码为:
auto && __range = range_expression;
auto __begin = begin_expr;
auto __end = end_expr;
for (; __begin != __end; ++__begin) {range_declaration = *__begin;loop_statement
}
观察伪代码,关于迭代器用到的运算符,用到了 * , != 和 前置++
所以我们需要对迭代器实现以下的内容
- *
- !=
- ++ (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 }观察伪代码࿰…...

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在各种医学图像分割挑战中取得了巨大成功。一些新的、带有花里胡哨功能的架构可能在某些数据集中在使用最佳超参数时取得成功,但它们…...
《操作系统真象还原》第一章 部署工作环境
ref: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
一、介绍 (1)服务注册中心 (2)管理各个服务上的application.yml,支持动态修改,但不会影响客户端配置 (3)一般将application.yml文件放在git上,客户端通过http/https方式…...
劣币驱良币的 pacing 之殇
都说 pacing 好 burst 孬(参见:为啥 pacing),就像都知道金币好,掺铁金币孬一样。可现实中掺铁的金币流通性却更好,劣币驱良币。劣币流通性好在卖方希望收到别人的良币而储存,而自己作为买方只使用劣币。 burst 和 pac…...
Gin 中的 Session(会话控制)
Session 介绍 session和cookie实现的底层目标是一致的,但是从根本而言实现的方法是不同的; session 是另一种记录客户状态的机制, 不同的是 Cookie 保存在客户端浏览器中,而 session保存 在服务器上 ; Session 的工作流程 当客户端浏览器第一次访问服务器并发送请求时,服…...

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

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做交易数据分析时,可以用talib库计算各类指标,这个库通过以下命令安装: pip install TA-Lib -i https://pypi.tuna.tsinghua.edu.cn/simple windows安装时可能出现本文标题所示的错误,可按如下步骤解决: 1、去…...
c 语言基础题目:L1-034 点赞
微博上有个“点赞”功能,你可以为你喜欢的博文点个赞表示支持。每篇博文都有一些刻画其特性的标签,而你点赞的博文的类型,也间接刻画了你的特性。本题就要求你写个程序,通过统计一个人点赞的纪录,分析这个人的特性。 …...

SaaS人力资源管理系统的Bug
SaaS人力资源管理系统的Bug Bug1【18】 这里我是直接把代码复制过来的,然后就有一个空白 这是因为它的代码有问题,原本的代码如下所示 <el-table-column fixed type"index" label"序号" width"50"></el-table…...
GPTQ 和 AWQ:LLM 量化方法的比较
大语言模型(LLM)在自然语言处理(NLP)任务中取得了显著的进展。然而,LLM 通常具有非常大的模型大小和计算复杂度,这限制了它们在实际应用中的部署。 量化是将浮点数权重转换为低精度整数的过程,…...

JVM:虚拟机类加载机制
JVM:虚拟机类加载机制 什么是JVM的类加载 众所周知,Java是面向对象编程的一门语言,每一个对象都是一个类的实例。所谓类加载,就是JVM虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验,转换解析和初始化&a…...
PHP筆記
前言因緣際會下還是開始學習php了。經歷了風風雨雨終於在今年暑假要去加拿大留學了,php會是第二年的其中一門必修課程,加上最近前端也真的蠻心累,也許有一門精進的後端語言,日後轉職會有更寬廣的道路,對自己說加油&…...

IDEA启动报错Failed to create JVM. JVM path的解决办法
今天启动IDEA时IDEA报错,提示如下。 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的消息时,我们经常会用到FlinkKafkaConsumer进行水位线的发送,本文就从源码看下FlinkKafkaConsumer.assignTimestampsAndWatermarks指定周期性水位线发送的流程 FlinkKafkaConsumer水位线发送 1.首先从Fetcher类开始,…...

Nginx:动静分离(示意图+配置讲解)
示意图: 动静分离 动静分离是指将动态内容和静态内容分开处理的一种方式。通常,动态内容是指由服务器端处理的,例如动态生成的网页、数据库查询等。静态内容是指不需要经过服务器端处理的,例如图片、CSS、JavaScript文件等。通过…...

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

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

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

TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)
文章目录 1.什么是Redis?2.为什么要使用redis作为mysql的缓存?3.什么是缓存雪崩、缓存穿透、缓存击穿?3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...

基于Flask实现的医疗保险欺诈识别监测模型
基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施,由雇主和个人按一定比例缴纳保险费,建立社会医疗保险基金,支付雇员医疗费用的一种医疗保险制度, 它是促进社会文明和进步的…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...
C++八股 —— 单例模式
文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全(Thread Safety) 线程安全是指在多线程环境下,某个函数、类或代码片段能够被多个线程同时调用时,仍能保证数据的一致性和逻辑的正确性…...

浪潮交换机配置track检测实现高速公路收费网络主备切换NQA
浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求,本次涉及的主要是收费汇聚交换机的配置,浪潮网络设备在高速项目很少,通…...

淘宝扭蛋机小程序系统开发:打造互动性强的购物平台
淘宝扭蛋机小程序系统的开发,旨在打造一个互动性强的购物平台,让用户在购物的同时,能够享受到更多的乐趣和惊喜。 淘宝扭蛋机小程序系统拥有丰富的互动功能。用户可以通过虚拟摇杆操作扭蛋机,实现旋转、抽拉等动作,增…...
django blank 与 null的区别
1.blank blank控制表单验证时是否允许字段为空 2.null null控制数据库层面是否为空 但是,要注意以下几点: Django的表单验证与null无关:null参数控制的是数据库层面字段是否可以为NULL,而blank参数控制的是Django表单验证时字…...

android RelativeLayout布局
<?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"android:gravity&…...