深入应用c++11读书笔记--使用c++11让程序更简洁、更现代-2.自己实现一个支持范围for循环的类~
来源:互联网 发布:3ds数据搬家 编辑:程序博客网 时间:2024/06/01 07:36
开头
之前写了部分关于c++11让程序更简洁相关内容,至于分出来第二部分,是由于之前都展示的一些纯语法相关并未主动编写代码,这里有一个需要编写一些代码的,所以单独摘出来。
让基于范围的for循环(支持自定义类型)
如何让基于范围的for循环运转
具体来说,基于范围的for循环只是普通for循环的语法糖,它需要查找容器的begin和end迭代器。
1. 对于普通array对象,begin将为array首地址,end为首地址加容器长度;
2. 容器是类对象,range-based for将试图通过查找类的begin()和end()定位;
3. 其他,通过全局begin和end定位。
实现对区间的迭代
namespace detail_range { template<typename T> class iterator { public: using value_type = T; using size_type = size_t; private: size_type cursor_; const value_type step_; value_type value_; public: iterator(size_type cur_start, value_type begin_val, value_type step_val) : cursor_(cur_start), step_(step_val), value_(begin_val) { value_ += (step_ * cursor_); } value_type operator*() const { return value_; } bool operator!=(const iterator& rhs) const { return cursor_ != rhs.cursor_; } iterator& operator++() { value_ += step_; ++cursor_; return *this; } }; template<typename T> class impl { public: using value_type = T; using reference = value_type&; using const_reference = const value_type&; using iterator = detail_range::iterator<value_type>; using const_iterator = const detail_range::iterator<value_type>; using size_type = typename iterator::size_type; private: const value_type begin_; const value_type end_; const value_type step_; const size_type max_count_; size_type get_adjusted_count() const { if (step_ > 0 && begin_ >= end_) { throw std::logic_error("when step > 0, end value must be greater than begin value"); } else if (step_ < 0 && begin_ <= end_) { throw std::logic_error("when step < 0, end value must be smaller than begin value"); } size_type count = static_cast<size_type>((end_ - begin_) / step_); if (begin_ + (step_ * count) != end_) { ++count; } return count; } public: impl(value_type begin_val, value_type end_val, value_type step_val) : begin_(begin_val) , end_(end_val) , step_(step_val) , max_count_(get_adjusted_count()) {} size_type size() const { return max_count_; } const_iterator begin() const { return{0, begin_, step_ }; } const_iterator end() const { return{ max_count_, begin_, step_ }; } }; template<typename T> impl<T> range(T end) { return{ {0}, end, 1 }; } template<typename T> impl<T> range(T begin, T end) { return{ begin, end, 1 }; } template<typename T, typename U> auto range(T begin, T end, U step)->impl<decltype(begin + step)> { using r_t = impl<decltype(begin + step)>; return r_t( begin, end, step ); }}
使用:
int main(){ for (auto i : detail_range::range(5, 20, 0.5)) { cout << i << endl; }}
以上代码主要摘抄书中的例子,有几点觉得书中写得很好:
- 实现impl中将类型进行了统一,避免了impl中的一些不必要的复杂度,然后在rang中将step和begin类型进行统一;
- using r_t = impl
尝试自己改造一个rang,支持从标准容器中间隔取值
附上代码吧,还缺少一些出错判断但能满足一般需求,待真实使用中进一步改进:
#pragma once#include <assert.h>namespace container_range { template<typename T> class iterator { public: using iterator_type = T; using size_type = size_t; using value_type = typename iterator_type::value_type; private: iterator_type cursor_; iterator_type end_; const int step_; public: iterator(iterator_type cur_start, iterator_type cur_end, int step_val) : cursor_(cur_start), end_(cur_end), step_(step_val) { assert(step_ >= 0); } value_type operator*() const { return *cursor_; } bool operator!=(const iterator& rhs) const { return cursor_ != rhs.cursor_; } iterator& operator++() { auto diff = std::distance(cursor_, end_); assert(diff >= 0); if (step_ < diff) { std::advance(cursor_, step_); } else { cursor_ = end_; } return *this; } }; template<typename ContainerT> class impl{ public: using container_type = ContainerT; using value_type = typename ContainerT::value_type; using const_reference = typename ContainerT::const_reference; using container_iterator_type = decltype(ContainerT().begin()); private: ContainerT container_; int step_; int begin_; public: impl(ContainerT container, int begin, int step) : container_(container), begin_(begin), step_(step) {} iterator<container_iterator_type> begin() { auto beginIt = container_.begin(); std::advance(beginIt, begin_); return{ beginIt, container_.end(), step_}; } iterator<container_iterator_type> end() { return{ container_.end(), container_.end(), step_}; } }; template<typename ContainerT> impl<ContainerT> range(ContainerT container, int begin, int step) { return{container, begin, step}; }}
下面是使用例子:
#include <iostream>#include "containerRange.h"#include <list>int main(){ std::list<int> l = {1, 2, 3, 4, 5, 6, 7}; for (auto i : container_range::range(l, 0, 2)) { // 从第一个1个元素开始取,间隔为2 std::cout << i << std::endl; } int v = 0; std::cin >> v; return 0;}
输出结果如下,满足初始设计要求。
1
3
5
7
0 0
- 深入应用c++11读书笔记--使用c++11让程序更简洁、更现代-2.自己实现一个支持范围for循环的类~
- 深入应用c++11读书笔记--使用c++11让程序更简洁、更现代-1
- 使用 C++11 让程序更简洁、更现代
- C++11新特性应用--让你的程序更简洁、更漂亮
- 让C程序更有效率
- c编程 如何让自己的代码更高效
- 让C程序更高效--持续完善
- 让C程序更高效的10种方法
- 让C程序更有效率的10种方法
- 让C程序更高效的10种方法
- 让C程序更高效的10种方法
- 让C程序更高效的10种方法
- 让C程序更高效的10种方法
- 让 C 程序更高效的 10 个建议
- 让 C 程序更高效的 10 个建议
- 让C程序更有效的十种方法
- 让c更有效率
- 使用MVP+Retrofit+rxjava让你的代码更简洁
- 使用FlashWavRecorder实现浏览器录制wav音频和上传音频文件,兼容IE8以上浏览器
- Jersey Response响应请求
- 漫谈redis在运维数据分析中的去重统计方式
- 305201 - Description: Check for duplicate invoices
- Web系统大规模并发——电商秒杀与抢购
- 深入应用c++11读书笔记--使用c++11让程序更简洁、更现代-2.自己实现一个支持范围for循环的类~
- 清博大数据API开放了,在开放API当中脱颖而出的竟然是他!!!!!!!
- 【Hacker Rank】04.Arithmetic Operators
- 插件原理整理
- 第11章:Sampling methods exercise 1-14
- PAT甲级1006
- IOS TableView的Cell高度自适应,UILabel自动换行适应
- MySQL 数据库 备份与恢复
- 最熟悉的陌生人:ListView 中的观察者模式