c++ range-based for loop sample

//z 2014-06-12 13:26:11 L.202'38029 BG57IV3@XCL T2508411853.K.F636940351 [T11,L175,R6,V152]

0. 形式

for ( declaration : expression ) statement

0.1 根据标准将会扩展成这样的形式:

1   {
2     auto&& __range = expression;
3     for (auto __begin = begin-expression,
4               __end = end-expression;
5          __begin != __end;
6          ++__begin)
7     {
8       declaration = *__begin;
9       statement
10    }
11  }

0.1.1  行3,4 ,begin 和 end 的判断规则:

The begin-expression and end-expression (lines 3 and 4) are determined as follows:

  • A. If expression is an array, then begin-expression and end-expressionare __range and __range + __bound, respectively, where __bound is the array bound.
  • B. If expression is of a class type that declares begin() and end()member functions, then begin-expression and end-expression are__range.begin() and __range.end(), respectively.
  • C. Otherwise, begin-expression and end-expression are begin(__range)and end(__range), respectively, where the begin() and end()functions are looked up using the argument-dependent lookup (ADL) which also includes the std namespace.

With arrays taken care of by the first rule, the second rule makes sure that all the standard containers as well as all the user-defined ones that follow the standard sequence interface will work with range-based for out of the box. For example, in ODB (an ORM for C++), we have the container-like result class template which allows iteration over the query result. Because it has the standard sequence interface with a forward iterator, we didn’t have to do anything extra to make it work with range-based for.

The last rule (the fallback to the free-standing begin()and end()functions) allows us to non-invasively adapt an existing container to the range-based for loop interface.

0.2 类型推断

std::vector<int> v = {1, 2, 3, 5, 7, 11};
const std::vector<int> cv = {1, 2, 3, 5, 7, 11};for (auto x: v) // x is int...;for (auto x: cv) // x is int...;for (auto& x: v) // x is int&...;for (auto& x: cv) // x is const int&

1.  例子

#include <iostream>
#include <vector>int main ()
{std::vector<int> data = { 1, 2, 3, 4 };for ( int datum : data ){std::cout << datum << std::endl;}
}
/*output
1
2
3
4
*/

2.  性能上的考虑
2.1 每次循环会创建一份 a 的拷贝

for(autoa : a_vec)
{
}

2.2 避免拷贝

for(constauto&a : a_vec)
{
}

3. 一个实现了 container semantics 的例子:

3.1 simple iterator

#include <iostream>using namespace std;// forward-declaration to allow use in Iter
class IntVector;class Iter
{
public:Iter(const IntVector* p_vec, int pos): _pos(pos), _p_vec(p_vec){ }// these three methods form the basis of an iterator for use with// a range-based for loopbooloperator!= (const Iter& other) const{return _pos != other._pos;}// this method must be defined after the definition of IntVector// since it needs to use itint operator* () const;const Iter& operator++ (){++_pos;// although not strictly necessary for a range-based for loop// following the normal convention of returning a value from// operator++ is a good idea.return *this;}private:int _pos;const IntVector *_p_vec;
};class IntVector
{
public:IntVector(){}int get(int col) const{return _data[col];}Iter begin() const{return Iter(this, 0);}Iter end() const{return Iter(this, 100);}void set(int index, int val){_data[index] = val;}private:int _data[100];
};int
Iter::operator* () const
{return _p_vec->get(_pos);
}// sample usage of the range-based for loop on IntVector
int main()
{IntVector v;for (int i = 0; i < 100; i++){v.set(i, i);}for (int i : v) { cout << i << endl; }
}

3.2 reverse iterator

template <typename T>
struct reverse_range
{
private:T& x_;public:reverse_range (T& x): x_ (x) {}auto begin () const -> decltype (this->x_.rbegin ()){return x_.rbegin ();}auto end () const -> decltype (this->x_.rend ()){return x_.rend ();}
};template <typename T>
reverse_range<T> reverse_iterate (T& x)
{return reverse_range<T> (x);
}std::vector<int> v = {1, 2, 3, 5, 7, 11};for (auto x: reverse_iterate (v))

4. 一个完整的例子 (编译出错,说找不到容器 begin end 实现)

#include <iostream>
#include <fstream>
#include <string>
#include <iterator>
#include <algorithm>
#include <unordered_map>template<classITERATOR>
ITERATOR begin( std::pair<ITERATOR,ITERATOR> &range )
{returnrange.first;
}template<classITERATOR>
ITERATOR end( std::pair<ITERATOR,ITERATOR> &range )
{returnrange.second;
}template<classT>
std::istream_iterator<T> begin(std::istream_iterator<T> &ii_stream)
{returnii_stream;
}template<classT>
std::istream_iterator<T> end(std::istream_iterator<T> &ii_stream)
{returnstd::istream_iterator<T>();
}intmain(intargc, char* argv[])
{std::ifstream data( "sowpods.txt");std::unordered_map<std::string,int> counts;std::unordered_multimap<std::string,std::string> words;for( conststd::string &s : std::istream_iterator<std::string>( data ) ){std::string temp = s;std::sort(temp.begin(), temp.end() );counts[temp]++;words.insert( std::make_pair(temp,s) );}auto ii = std::max_element( counts.begin(), counts.end(),[](conststd::pair<std::string,int> &v1, conststd::pair<std::string,int> &v2){returnv1.second < v2.second; });std::cout << "The maximum anagram family has " << ii->second << " members:\n";for( constauto &map_entry : words.equal_range( ii->first ) )std::cout << map_entry.second << " ";std::cout << std::endl;return0;
}

//z 2014-06-12 13:26:11 L.202'38029 BG57IV3@XCL T2508411853.K.F636940351 [T11,L175,R6,V152]
5. 一些 wrapper 或 iterator 例子

#include <memory>
#include <iterator>/*  Only provides the bare minimum to support range-based for loops.Since the internal iterator of a range-based for is inaccessible,there is no point in more functionality here. */
template< typename iter >
struct range_iterator_reference_wrapper: std::reference_wrapper< iter > {iter &operator++() { return ++ this->get(); }decltype( * std::declval< iter >() ) operator*() { return * this->get(); }range_iterator_reference_wrapper( iter &in ): std::reference_wrapper< iter >( in ) {}friend bool operator!= ( range_iterator_reference_wrapper const &l,range_iterator_reference_wrapper const &r ){ return l.get() != r.get(); }
};namespace unpolluted {/*  Cannot call unqualified free functions begin() and end() from within a class with members begin() and end() without this hack. */template< typename u >auto b( u &c ) -> decltype( begin( c ) ) { return begin( c ); }template< typename u >auto e( u &c ) -> decltype( end( c ) ) { return end( c ); }
}template< typename iter >
struct range_proxy {range_proxy( iter &in_first, iter in_last ): first( in_first ), last( in_last ) {}template< typename T >range_proxy( iter &out_first, T &in_container ): first( out_first ),last( unpolluted::e( in_container ) ) {out_first = unpolluted::b( in_container );}range_iterator_reference_wrapper< iter > begin() const{ return first; }range_iterator_reference_wrapper< iter > end(){ return last; }iter &first;iter last;
};template< typename iter >
range_proxy< iter > visible_range( iter &in_first, iter in_last ){ return range_proxy< iter >( in_first, in_last ); }template< typename iter, typename container >
range_proxy< iter > visible_range( iter &first, container &in_container ){ return range_proxy< iter >( first, in_container ); }

Usage:

#include <vector>
#include <iostream>
std::vector< int > values{ 1, 3, 9 };int main() {// Either provide one iterator to see it through the whole container...std::vector< int >::iterator i;for ( auto &value : visible_range( i, values ) )std::cout << "# " << i - values.begin() << " = " << ++ value << '\n';// ... or two iterators to see the first incremented up to the second.auto j = values.begin(), end = values.end();for ( auto &value : visible_range( j, end ) )std::cout << "# " << j - values.begin() << " = " << ++ value << '\n';
}
for(auto i : ForIterator(some_list)) {// i is the iterator, which was returned by some_list.begin()// might be useful for whatever reason
}

The implementation was not that difficult:

template <typename T> struct Iterator {T& list;typedef decltype(list.begin()) I;struct InnerIterator {I i;InnerIterator(I i) : i(i) {}I operator * () { return i; }I operator ++ () { return ++i; }bool operator != (const InnerIterator& o) { return i != o.i; }};Iterator(T& list) : list(list) {}InnerIterator begin() { return InnerIterator(list.begin()); }InnerIterator end() { return InnerIterator(list.end()); }
};
template <typename T> Iterator<T> ForIterator(T& list) {return Iterator<T>(list);
}

//z 2014-06-12 13:26:11 L.202'38029 BG57IV3@XCL T2508411853.K.F636940351 [T11,L175,R6,V152]
6. auto 部分的简单指导原则:
auto x : 使用拷贝
auto &x : 使用引用,指向原item,并且可能变更其值
const auto&x :指向原item,并且保证不改变其值

7. MAP 例子

Each element of the container is a map<K, V>::value_type, which is a typedef for std::pair<const K, V>. Consequently, you'd write this as

for (auto& kv : myMap) {std::cout << kv.first << " has value " << kv.second << std::endl;
}

如前所述,为效率考虑,使用reference,如果不改变其值(如这里),还应该加上 const 。

8. 来自 ms 的例子

Executes statement repeatedly and sequentially for each element in expression.

for ( for-range-declaration : expression ) statement

Remarks

Use the range-based for statement to construct loops that must execute through a "range", which is defined as anything that you can iterate through—for example, std::vector, or any other STL sequence whose range is defined by a begin() and end(). The name that is declared in the for-range-declaration portion is local to the for statement and cannot be re-declared in expression or statement. Note that the auto keyword is preferred in the for-range-declaration portion of the statement.

This code shows how to use ranged for loops to iterate through an array and a vector:

C++
// range-based-for.cpp
// compile by using: cl /EHsc /nologo /W4
#include <iostream>
#include <vector>
using namespace std;int main()
{// Basic 10-element integer array.int x[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };// Range-based for loop to iterate through the array.for( int y : x ) { // Access by value using a copy declared as a specific type. // Not preferred.cout << y << " ";}cout << endl;// The auto keyword causes type inference to be used. Preferred.for( auto y : x ) { // Copy of 'x', almost always undesirablecout << y << " ";}cout << endl;for( auto &y : x ) { // Type inference by reference.// Observes and/or modifies in-place. Preferred when modify is needed.cout << y << " ";}cout << endl;for( const auto &y : x ) { // Type inference by reference.// Observes in-place. Preferred when no modify is needed.cout << y << " ";}cout << endl;cout << "end of integer array test" << endl;cout << endl;// Create a vector object that contains 10 elements.vector<double> v;for (int i = 0; i < 10; ++i) {v.push_back(i + 0.14159);}// Range-based for loop to iterate through the vector, observing in-place.for( const auto &j : v ) {cout << j << " ";}cout << endl;cout << "end of vector test" << endl;
}

Here is the output:

1 2 3 4 5 6 7 8 9 10

1 2 3 4 5 6 7 8 9 10

1 2 3 4 5 6 7 8 9 10

1 2 3 4 5 6 7 8 9 10

end of integer array test

0.14159 1.14159 2.14159 3.14159 4.14159 5.14159 6.14159 7.14159 8.14159 9.14159

end of vector test

A range-based for loop terminates when one of these in statement is executed: a break, return, or goto to a labeled statement outside the range-based for loop. A continue statement in a range-based for loop terminates only the current iteration.

Keep in mind these facts about range-based for:

  • Automatically recognizes arrays.

  • Recognizes containers that have .begin() and .end().

  • Uses argument-dependent lookup begin() and end() for anything else.

转载于:https://www.cnblogs.com/IS2120/p/6745652.html

c++11 : range-based for loop相关推荐

  1. using(别名)和range based for

    using(别名)替代typedef 关键字 using 语法 别名声明是具有下列语法的声明: using 标识符 attr(可选) = 类型标识 ; (1) template < 模板形参列表 ...

  2. 使用 C++11 Range For-Loop 枚举注册表、文件夹和 WMI

    使用 C++11 range for-loop 来枚举 Windows 注册表键/值.文件夹中的文件和 Windows Management Instrumentation (WMI) 查询,可以不需 ...

  3. c++用数组初始化向量_用C ++初始化向量

    c++用数组初始化向量 In this article, we'll take a look at some of the ways to initialize a vector in C++. Th ...

  4. VS2017 C++开发环境插件推荐

    文章目录 引言 VS2017安装 Assistx安装 代码高亮 快速插入代码模板 模板介绍 新建模板 常用模板汇总 文件头说明cmh 函数注释cmf 防重复包含chg c++11 Range-Base ...

  5. Web版简易加法计算

    ##HTTP HTTP是一个客户端和服务器端请求和应答的标准(TCP).客户端是终端用户,服务器端是网站.通过使用Web浏览器.网络爬虫或者其它的工具,客户端发起一个到服务器上指定端口(默认端口为80 ...

  6. Bash For Loop Examples for Your Linux Shell Scripting--ref

    There are two types of bash for loops available. One using the "in" keyword with list of v ...

  7. Python|线程和进程|阻塞|非阻塞|同步|异步|生成器和协程|资源竞争|进程间通信|aiohttp库|daemon属性值详解|语言基础50课:学习(11)

    文章目录 系列目录 原项目地址 第34课:Python中的并发编程-1 线程和进程 多线程编程 使用 Thread 类创建线程对象 继承 Thread 类自定义线程 使用线程池 守护线程 资源竞争 G ...

  8. java11 是长期支持_这里有你不得不了解的Java 11版本特性说明

    「MoreThanJava」 宣扬的是 「学习,不止 CODE」,本系列 Java 基础教程是自己在结合各方面的知识之后,对 Java 基础的一个总回顾,旨在 「帮助新朋友快速高质量的学习」. 当然 ...

  9. 表分区MySQL版本:5.5.11比5.1查询速度明显提高(4倍左右)

    实验1 1.建表: create table `t_part_test`( `id` int NOT NULL default 0, `detail` char(32) NOT NULL defaul ...

  10. python基础教程:list转换range()的打印结果

    for循环中常见的一个函数是range(),然而有时候直接打印range的时候,得到的结果却不是我们想要的,这个时候,可以用list列表来转换一下range的结果,让我们更清除的打印出range中的元 ...

最新文章

  1. makefile 中 =, :=, ?=, +=的区别
  2. Pytorch中的variable, tensor与numpy相互转化
  3. python asyncio和celery对比_如何将Celery与asyncio结合? - python
  4. linux之hexdump命令
  5. ListView控件获取选中项的内容 c# 114867417
  6. 解决ubuntu中zip解压的中文乱码问题
  7. linux-libre 电脑,[图]没有任何专有代码 GNU Linux-libre 5.1-gnu内核正式发布
  8. C++ select模型聊天室初版
  9. surfer画世界频率分布图(等高线、地点标注)
  10. android下最强的3款pdf阅读器测评
  11. win10修改命令行默认字体
  12. Windows安装Java8以及环境变量的配置(图解以及java安装包下载)
  13. 服务器网口聚合操作文档,服务器网口聚合怎么操作
  14. 商户/服务商微信支付开发文档【 直连模式/服务商模式】如何在公众号、小程序中接入微信支付?
  15. ODT在手,DDR5布线可以任性走?
  16. ECCV2022 | 生成对抗网络GAN论文汇总(图像转换-图像编辑-图像修复-少样本生成-3D等)...
  17. iOS支付指南:POS终端刷卡流程、银联55域TLV子域信息说明、银联前置、NFC
  18. 先人들의 白頭山 登程路
  19. ccf z字形 java,Java具有简单、 __________ 、稳定、与平台无关、解释型、多线程、动态等特点。...
  20. 嵌入式开发(四):海思Hi3559AV100交叉编译ffmpeg

热门文章

  1. php 5.5.12 服务器php.ini配置
  2. Feign 简介与使用入门,请求、响应压缩,日志记录
  3. 阶段3 2.Spring_04.Spring的常用注解_1 今日课程内容介绍
  4. Vue项目需求实现记录总目录(永久更新)
  5. 十大经典排序算法总结 (Python)
  6. Android Studio模拟器磁盘空间不足(Not enough disk space to run AVD)
  7. java日期互转:LocalDateTime、String、Instant、Date
  8. sqlite配置下载安装教程
  9. DeBruijin HDU - 2894(????????)
  10. 零基础Python知识点回顾(三)