博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
c++11 : range-based for loop
阅读量:5171 次
发布时间:2019-06-13

本文共 12314 字,大约阅读时间需要 41 分钟。

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       statement10    }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
v = {1, 2, 3, 5, 7, 11};const std::vector
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 
#include
int main (){ std::vector
data = { 1, 2, 3, 4 }; for ( int datum : data ) { std::cout << datum << std::endl; }}
/*output1234*/
2.  性能上的考虑
2.1 每次循环会创建一份 a 的拷贝

for
(
auto
a : a_vec)
{
}
2.2 避免拷贝
for
(const
auto&
a : a_vec)
{
}

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

3.1 simple iterator

#include 
using namespace std;// forward-declaration to allow use in Iterclass 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 loop bool operator!= (const Iter& other) const { return _pos != other._pos; } // this method must be defined after the definition of IntVector // since it needs to use it int 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];};intIter::operator* () const{ return _p_vec->get(_pos);}// sample usage of the range-based for loop on IntVectorint 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 
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
reverse_range
reverse_iterate (T& x){  return reverse_range
(x);} std::vector
v = {1, 2, 3, 5, 7, 11}; for (auto x: reverse_iterate (v))
4. 一个完整的例子 (
编译出错,说找不到容器 begin end 实现)
#include 
#include
#include
#include
#include
#include
template
ITERATOR begin( std::pair
&range ){ returnrange.first;} template
ITERATOR end( std::pair
&range ){ returnrange.second;} template
std::istream_iterator
begin(std::istream_iterator
&ii_stream){ returnii_stream;} template
std::istream_iterator
end(std::istream_iterator
&ii_stream){ returnstd::istream_iterator
();} intmain(intargc, char* argv[]){ std::ifstream data( "sowpods.txt"); std::unordered_map
counts; std::unordered_multimap
words; for( conststd::string &s : std::istream_iterator
( 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
&v1, conststd::pair
&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 
#include
/* 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 
#include
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 
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
Iterator
ForIterator(T& list) {
return Iterator
(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

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  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:

// range-based-for.cpp// compile by using: cl /EHsc /nologo /W4#include 
#include
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 undesirable cout << 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
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 , , or  to a labeled statement outside the range-based for loop. A  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

你可能感兴趣的文章
STL中的set使用方法详细!!!!
查看>>
sealed关键字的作用
查看>>
Android系统Surface机制的SurfaceFlinger服务简要介绍和学习计划
查看>>
HDU - 4472 Count
查看>>
搭建测试环境
查看>>
调用链监控 CAT 之 入门
查看>>
flexbox属性速览及常见布局实现
查看>>
zlib在Linux和windows中的使用
查看>>
rabbitMq实战使用
查看>>
JQuery Easyui/TopJUI表格基本的删除功能(删除当前行和多选删除)
查看>>
javascript 倒计时
查看>>
web前端工程师入门须知
查看>>
linux--->linux 各个文件夹及含义
查看>>
欢迎使用CSD横竖屏切换问题占位
查看>>
2016集训测试赛(二十)Problem B: 字典树
查看>>
中文保存在properties乱码的解决
查看>>
poj题目分类
查看>>
idea 配置mybatis Generator 不显示的解决方案 和 配置MBG
查看>>
英语生疏了,每日至少一句吧
查看>>
创建打不开文件夹
查看>>