深入应用c++11读书笔记--使用c++11让程序更简洁、更现代-2.自己实现一个支持范围for循环的类~
2016-11-16 20:41
1031 查看
开头
之前写了部分关于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
相关文章推荐
- 深入应用c++11读书笔记--使用c++11让程序更简洁、更现代-1
- 深入理解Python中协程的应用机制: 使用纯Python来实现一个操作系统吧!!
- 使用 C++11 让程序更简洁、更现代
- 深入理解Python中协程的应用机制: 使用纯Python来实现一个操作系统吧!!
- 深入理解Python中协程的应用机制: 使用纯Python来实现一个操作系统吧!!
- C#--第2周实验--任务四--编写一个控制台应用--分别使用for,while,do-while循环语句计算 n!
- C#之使用NotifyIcon实现任务栏托盘菜单,图标闪烁效果及气泡提示 很多程序是只需要后台运行的,甚至不需要自己的应用界面。NotifyIcon提供了程序在任务栏的显示功能 程序下载链接如下
- C++11新特性:range based for loop-范围for循环基本使用方法
- 使用多线程方法实现一个死锁程序,用来提醒自己不要犯这样的错误
- 深入理解Python中协程的应用机制: 使用纯Python来实现一个操作系统吧!!
- 深入理解Python中协程的应用机制: 使用纯Python来实现一个操作系统吧!!
- 【C++ STL应用与实现】26: 如何使用std::for_each以及基于范围的for循环 (since C++11)
- 代码实现从我的主窗体里打开另外一个应用程序,并且让该程序像自己的MDI子窗体那样在父窗体的范围内显示
- 深入理解Python中协程的应用机制: 使用纯Python来实现一个操作系统吧!!
- python cgi ajax - 使用CGIHTTPServer实现一个ajax程序
- c++自己实现的一个程序
- 使用管道编程----利用别人的程序,实现自己的功能
- NET简单的一个画图程序 使用简单 自己可以相关自己的内容进行配置就可以使用了
- 一个使用JAVA编写的类似按键精灵的程序,支持脚本文件编写(含源代码)
- 使用gtype构造的一个简单学生管理程序其他属性自己加