C++11的for循环,以及范围Range类的实现
C++11支持range-based for循环。这是一个很方便的特性,能省挺多代码。以下代码就能很方便的遍历vector中的元素,并打印出来:
1
2
3
4
5
6
7
8
|
std::vector< int > int_vec; int_vec.push_back(1); int_vec.push_back(2); //如果要修改int_vec中的元素,将变量x声明为 int& 即可 for ( int x: int_vec) { std::cout << x << endl; } |
可以遍历的对象包括:
- 数组。(不包括指针)
- 定义了begin()和end()方法,且返回该方法返回迭代器的类对象。(STL 中所有容器都可以)
(对于动态生成的数组的遍历,用下面介绍的Range类也能省不少代码)
参考http://en.cppreference.com/w/cpp/language/range-for 可知,
语句 for (
range_declaration :
range_expression)
loop_statement
与以下语句作用等价:
1
2
3
4
5
6
7
8
9
|
{ auto && __range = range_expression ; for ( auto __begin = begin_expr, __end = end_expr; __begin != __end; ++__begin) { range_declaration = *__begin; loop_statement } } |
对于可遍历的类对象,__begin和__end分别由类的begin()和end()方法产生。且由于__range变量是右值引用,如果range_expression的结果是右值,其将会在循环结束后析构。
这样,C++11终于支持了这种现代编程语言都支持的遍历方式了。但是,无论是语法还是标准库都不支持对具体数字的遍历,比如python中的 for i in xrange(1,5)语句中,x将连续取[1,4]中的值。(Boost库有irange类可以满足这个需求,但是下面会讨论下我的实现)
最直接的方法,就是写一个函数,返回一个vector<int>对象,其元素为从begin到end的值。但这样每次循环时都得构造一个这样的对象,略慢。
从标准来看,如果一个类要支持这样遍历,至少得有begin()和end()方法。在for循环的初始化部分,调用了这两个方法之后,就没这个类啥事了——都是迭代器的事。所以很自然,从迭代器上下手。这个迭代器必须支持三种操作:!=,前缀++,解引用。有没发现,如果这个“迭代器”是个int数值的话,上面循环中的__begin!=__end;++__begin语句就是一个非常自然的实现。现在的目标很简单了:这个“迭代器”不遍历容器中的每个元素,而就是一个简单的int数值的封装。对其解引用将返回这个数,而比较和自加操作均对这个数进行操作。
有想法之后,实现起来就很容易了。首先定义一个仿迭代器 FakeIter ,其对一个数值进行封装,并重载必须的操作符。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
class FakeIter { typedef long _VType; //数值的类型为long。当然了,也可以写个模板出来 public : explicit FakeIter(_VType val) :value_(val){} bool operator != ( const FakeIter& other) const { return ( this ->GetValue()) != (other.GetValue()); } _VType operator* () const { return GetValue(); } const FakeIter& operator++ () { ++value_; return * this ; } private : _VType GetValue() const { return value_; } _VType value_; }; |
至于“容器”类的实现,就更简单了:实现begin()和end()方法,并返回上面的FakeIter就好了。类中的方法加了一些cout语句,可以更清楚的了解循环执行时具体方法的调用过程,实际用时可以删掉。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
class Range { typedef long _VType; //同样,也可以弄个模板出来,但是就不方便用了 public : Range (_VType begin_v, _VType end_v) :begin_value_(begin_v), end_value_(end_v) { cout<< "Range::Range()" <<endl; } ~Range() { cout<< "Range::~Range()" <<endl; } FakeIter begin () const { cout<< "Range::begin()" <<endl; return FakeIter(begin_value_); } FakeIter end () const { cout<< "Range::end()" <<endl; return FakeIter(end_value_ ); } private : _VType begin_value_; _VType end_value_; }; |
好了,试试看这货有没用:
1
2
3
4
5
|
for ( auto x: Range(1,5)) { std::cout<<x<<endl; } std::cout<< "Loop end" <<endl; |
在vs2012及clang下输出如下:
Range::Range()
Range::begin()
Range::end()
1
2
3
4
Range::~Range()
Loop end
嗯,如果把那些影响视线的输出语句的注释掉的话貌似能用了。现在要遍历一个new生成的数组的话,只需用这东西Range个下标,世界就清静了。
但是,步长呢!好吧,貌似我暂时还没这方面的需求。不过实现起来也很简单:修改FakeIter类就可以了,可以增加一个表示步长的成员,然后再修改自加操作。更进一步,也可以加一个生成器方法,就能变成一个更通用的生成器了。配合C++11 lambda操作符,用起来也挺方便。
C++11的for循环,以及范围Range类的实现的更多相关文章
- C++11之for循环的新用法
C++使用如下方法遍历一个容器: #include "stdafx.h" #include<iostream> #include<vector> int m ...
- python循环for,range,xrange;while
>>>range(1,5)#代表从1到5(不包含5) [1,2,3,4] >>>range(1,5,2)#代表从1到5,间隔2(不包含5) [1,3] >&g ...
- C++11之for循环的新用法《转》
相关资料:https://legacy.gitbook.com/book/changkun/cpp1x-tutorial/details C++11之for循环的新用法 C++使用如下方法遍历一个容器 ...
- 第二天:python的函 数、循环和条件、类
https://uqer.io/community/share/54c8af17f9f06c276f651a54 第一天学习了Python的基本操作,以及几种主要的容器类型,今天学习python的函数 ...
- Android的消息循环机制 Looper Handler类分析
Android的消息循环机制 Looper Handler类分析 Looper类说明 Looper 类用来为一个线程跑一个消息循环. 线程在默认情况下是没有消息循环与之关联的,Thread类在ru ...
- C++ 实现Range类,用于常规遍历
PYTHON的Range类非常好用,所以用C++来简单实现下: // 实现Range类,用于遍历 // #include <string> class Range { public: / ...
- 【TODO】Ruby Range类
创建: 2017/10/28 Range类 ...
- Kotlin 区间和循环 Loop和Range
在kotln中有一种很简单的方式来表达某一个区间的数字. 比如我想存储1~100. 我在其他的语言中可以用数组,步骤大概有三个把. 但是在kotlin中就只需要一步. 代码如下: fun main(a ...
- 第11月第11天 avplayer循环播放
1. /* Setting actionAtItemEnd to None prevents the movie from getting paused at item end. A very sim ...
随机推荐
- 【转载】应读者强烈要求给出《超容易的Linux系统管理入门书》一书的主要知识点
刚开始了一篇连载,收到广大Linux爱好者的反馈,非常欣慰.大家对Linux学习感到很迷茫,不知道学哪些内容,如何学习? <超容易的Linux系统管理入门书>一书是腾讯Linux专家在腾讯 ...
- zz 李治国:地图大战本质是争抢O2O入口
导航免费,这一天早该到来了!高德.百度免费之争,其实也是为了抢占生活服务这一最关键的入口,从而获得该战场的翻盘机会. 导航地图免费,实则是生活服务的入口之争.我在08年时就在阿里内部讲过这个事,并建议 ...
- Junit的最简单样例:Hello world!
我的技术博客经常被流氓网站恶意爬取转载.请移步原文:http://www.cnblogs.com/hamhog/p/3824934.html,享受整齐的排版.有效的链接.正确的代码缩进.更好的阅读体验 ...
- 清理c盘垃圾(将一下代码复制到记事本然后把后缀名改为xxx.bat,然后双击,就ok了!!)
@echo off echo 正在清除系统垃圾文件,请稍等...... del /f /s /q %systemdrive%\*.tmp del /f /s /q %systemdrive%\*._m ...
- JS 正则 获取URL参数
function getQueryString(name) { var reg = new RegExp("(^|&)" + name + "=([^&] ...
- DTCMS会员中心快速更改样式思路
非常简便 制作一个public.css文件,包含网站头部和底部的样式代码 每个会员中心模版导入这个文件就可以 把原先style.css的头部和底部样式代码删除
- 利用WeX5集成百度地图
最近做一个地图类的app经过几天的摸索,终于完成百度地图集成的界面先看效果:1.加载完成之后,页面加载制定位置的地图2.顶部能够输入地图的关键字,地图显示符合条件的下拉列表3.用户选择了相应的选项后, ...
- mongodb下如何开启不同端口,本地远程ip的服务器呢
mongod --bind_ip 10.0.10.27 --port 28000 像这样可以绑定ip,绑定地址
- ubuntu更新源,简单两步搞定
1.启动器中打开Ubuntu软件中心 2.鼠标顶部面板点击编辑选择软件源(163.sohu) 搞定!
- Python数据结构——二叉树的实现
1. 二叉树 二叉树(binary tree)中的每个节点都不能有多于两个的儿子. 1.1 二叉树列表实现 如上图的二叉树可用列表表示: tree=['A', #root ['B', #左子树 ['D ...