c++11 : range-based for loop

时间:2022-07-14 14:28:39

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.  例子

 

[cpp]  view plain copy c++11 : range-based for loop c++11 : range-based for loop
 
  1. #include <iostream>  
  2. #include <vector>  
  3.   
  4.   
  5. int main ()  
  6. {  
  7.     std::vector<int> data = { 1, 2, 3, 4 };  
  8.   
  9.   
  10.     for ( int datum : data )  
  11.     {  
  12.         std::cout << datum << std::endl;  
  13.     }  
  14. }  
[cpp]  view plain copy c++11 : range-based for loop c++11 : range-based for loop
 
  1. /*output 
  2. */  

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

 

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

 

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

3.1 simple iterator

[cpp]  view plain copy c++11 : range-based for loop c++11 : range-based for loop
 
  1. #include <iostream>  
  2.   
  3. using namespace std;  
  4.   
  5. // forward-declaration to allow use in Iter  
  6. class IntVector;  
  7.   
  8. class Iter  
  9. {  
  10. public:  
  11.     Iter(const IntVector* p_vec, int pos)  
  12.         : _pos(pos)  
  13.         , _p_vec(p_vec)  
  14.     { }  
  15.   
  16.     // these three methods form the basis of an iterator for use with  
  17.     // a range-based for loop  
  18.     bool  
  19.         operator!= (const Iter& other) const  
  20.     {  
  21.         return _pos != other._pos;  
  22.     }  
  23.   
  24.     // this method must be defined after the definition of IntVector  
  25.     // since it needs to use it  
  26.     int operator* () const;  
  27.   
  28.     const Iter& operator++ ()  
  29.     {  
  30.         ++_pos;  
  31.         // although not strictly necessary for a range-based for loop  
  32.         // following the normal convention of returning a value from  
  33.         // operator++ is a good idea.  
  34.         return *this;  
  35.     }  
  36.   
  37. private:  
  38.     int _pos;  
  39.     const IntVector *_p_vec;  
  40. };  
  41.   
  42. class IntVector  
  43. {  
  44. public:  
  45.     IntVector()  
  46.     {  
  47.     }  
  48.   
  49.     int get(int col) const  
  50.     {  
  51.         return _data[col];  
  52.     }  
  53.     Iter begin() const  
  54.     {  
  55.         return Iter(this, 0);  
  56.     }  
  57.   
  58.     Iter end() const  
  59.     {  
  60.         return Iter(this, 100);  
  61.     }  
  62.   
  63.     void set(int index, int val)  
  64.     {  
  65.         _data[index] = val;  
  66.     }  
  67.   
  68. private:  
  69.     int _data[100];  
  70. };  
  71.   
  72. int  
  73. Iter::operator* () const  
  74. {  
  75.     return _p_vec->get(_pos);  
  76. }  
  77.   
  78. // sample usage of the range-based for loop on IntVector  
  79. int main()  
  80. {  
  81.     IntVector v;  
  82.     for (int i = 0; i < 100; i++)  
  83.     {  
  84.         v.set(i, i);  
  85.     }  
  86.     for (int i : v) { cout << i << endl; }  
  87. }  



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 实现)
[cpp]  view plain copy c++11 : range-based for loop c++11 : range-based for loop
 
  1. #include <iostream>  
  2. #include <fstream>  
  3. #include <string>  
  4. #include <iterator>  
  5. #include <algorithm>  
  6. #include <unordered_map>  
  7.    
  8. template<classITERATOR>  
  9. ITERATOR begin( std::pair<ITERATOR,ITERATOR> &range )  
  10. {  
  11.     returnrange.first;  
  12. }  
  13.    
  14. template<classITERATOR>  
  15. ITERATOR end( std::pair<ITERATOR,ITERATOR> &range )  
  16. {  
  17.     returnrange.second;  
  18. }  
  19.    
  20. template<classT>  
  21. std::istream_iterator<T> begin(std::istream_iterator<T> &ii_stream)  
  22. {  
  23.     returnii_stream;  
  24. }  
  25.    
  26. template<classT>  
  27. std::istream_iterator<T> end(std::istream_iterator<T> &ii_stream)  
  28. {  
  29.     returnstd::istream_iterator<T>();  
  30. }  
  31.    
  32. intmain(intargc, char* argv[])  
  33. {  
  34.     std::ifstream data( "sowpods.txt");  
  35.     std::unordered_map<std::string,int> counts;  
  36.     std::unordered_multimap<std::string,std::string> words;  
  37.    
  38.     for( conststd::string &s : std::istream_iterator<std::string>( data ) )  
  39.     {  
  40.         std::string temp = s;  
  41.         std::sort(temp.begin(), temp.end() );  
  42.         counts[temp]++;  
  43.         words.insert( std::make_pair(temp,s) );  
  44.     }  
  45.     auto ii = std::max_element( counts.begin(),   
  46.                                 counts.end(),  
  47.                                 [](conststd::pair<std::string,int> &v1,   
  48.                                    conststd::pair<std::string,int> &v2)  
  49.                                 {  
  50.                                     returnv1.second < v2.second;   
  51.                                 }  
  52.                               );  
  53.     std::cout << "The maximum anagram family has " << ii->second << " members:\n";  
  54.     for( constauto &map_entry : words.equal_range( ii->first ) )  
  55.         std::cout << map_entry.second << " ";  
  56.     std::cout << std::endl;  
  57.     return0;  
  58. }  


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