c++11 : range-based for loop

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 plaincopy

  1. #include <iostream>
  2. #include <vector>
  3. int main ()
  4. {
  5. std::vector<int> data = { 1, 2, 3, 4 };
  6. for ( int datum : data )
  7. {
  8. std::cout << datum << std::endl;
  9. }
  10. }

[cpp] view plaincopy

  1. /*output
  2. 1
  3. 2
  4. 3
  5. 4
  6. */

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

for(autoa : a_vec)

{

}


2.2 避免拷贝

for(constauto&a : a_vec)

{

}

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

3.1 simple iterator

[cpp] view plaincopy

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

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 plaincopy

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

//z 2014-06-12 13:26:11 L.202‘38029 [email protected] 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 [email protected] 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 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<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 breakreturn, 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.
时间: 2024-10-28 13:10:21

c++11 : range-based for loop的相关文章

Performance Modeling of IEEE 802.11 DCF Based Fair Channel Access for Vehicular-to-Roadside Communication in a Non-Saturated State

作者:吴琼(东南大学博士) 一.摘要 本文考虑了车辆自组网中的公平接入问题,建立了一个分析模型,分析了基于IEEE 802.11 DCF的非饱和状态下的公平信道接入协议的性能.推导了非饱和状态下,车辆的最小竞争窗口大小与车辆的传输概率之间的关系,以及车速与车辆的最小竞争窗口大小之间的关系.基于该分析模型,可以确定给定速度下车辆的最小竞争窗口大小,以实现不同车辆之间的公平竞争.仿真结果验证了该分析模型的有效性. 二.前言 在车辆自组网(VANET)中,通信可能发生在车辆之间或车辆与路边单元或接入点

c++11介绍

C++11标准是 ISO/IEC 14882:2011 - Information technology -- Programming languages -- C++ 的简称[1]  . C++11标准由国际标准化组织(ISO)和国际电工委员会(IEC)旗下的C++标准委员会(ISO/IEC JTC1/SC22/WG21)于2011年8月12日公布[2]  ,并于2011年9月出版.2012年2月28日的国际标准草案(N3376)是最接近于C++11标准的草案(仅编辑上的修正).此次标准为C+

C++11简介(1)

原文地址:http://www.codeproject.com/Articles/312029/Cplusplus-A-Glance-part-of-n 1.介绍 C++0x现在是一个正式标准了,被称作C++11.ISO C++在2011年正式通过这个标准.这篇文章的目的是浏览C++11的特性和介绍VS2010中支持的特性,且可以作为你研究个别特性的一个开端. 因为长度原因,文章被分为了几部分.我自己也十分害怕一次性阅读那么长的文档,再说一次把C++11特性写完将会是工作变得无聊. 这是我在co

变量引用的错误:UnboundLocalError: local variable &#39;range&#39; referenced before assignment

1 class Battery(): 2 """一次模拟电动汽车电瓶的简单尝试""" 3 def __init__(self,battery_size=70): 4 self.battery_size = battery_size 5 # self.range =range 6 def describe_battery(self): 7 print(self.battery_size) 8 9 def get_range(self): 10 pr

Day1_Python基础_14.表达式for loop

最简单的循环10次 #_*_coding:utf-8_*_ __author__ = 'Alex Li' for i in range(10): print("loop:", i ) 输出 loop: 0 loop: 1 loop: 2 loop: 3 loop: 4 loop: 5 loop: 6 loop: 7 loop: 8 loop: 9 需求一:还是上面的程序,但是遇到小于5的循环次数就不走了,直接跳入下一次循环 for i in range(10): if i<5:

Python 函数 -range()

range() pytho range() 函数可创建一个整数列表,一般用在 for 循环中. 语法: range(start, stop[, step]) start: 计数从 start 开始.默认是从 0 开始.例如range(5)等价于range(0, 5); end: 计数到 end 结束,但不包括 end.例如:range(0, 5) 是[0, 1, 2, 3, 4]没有5 step:步长,默认为1.例如:range(0, 5) 等价于 range(0, 5, 1) 实例: 1 >>

汇编语言——[bx]和loop指令

[bx] 由于在编译器中mov AX,[0]指令会被编译器认为是mov AX,0所以引入[bx]的概念 mov [bx],AX的意思是将(ds)*16+(bx)内存位置的值赋给AX 用法和之前的ds[address]一样 小Tips 1 ; [bx]的使用方法 2 mov ax,1000H 3 4 mov bx,2000H 5 6 mov ds,ax ; 将ds数据段寄存器赋值为2000H 7 8 mov [bx],ax ; 将ax寄存器的值赋给内存单元21000H位置 9 10 ; 其他方式

python基础--list转换range()的打印结果

for循环中常见的一个函数是range(),然而有时候直接打印range的时候,得到的结果却不是我们想要的,这个时候,可以用list列表来转换一下range的结果,让我们更清除的打印出range中的元素. 例如: s=10 d=5 for i in range(s,s+d): s=s+1 print(s) print(i) print(range(s, s + d, 1)) print(list(range(s,s+d,1))) 运行结果: 1110range(11, 16)[11, 12, 1

python3 之 内置函数range()

一.语法: range(stop) range(start,stop,step) start:计数从start开始,默认是从0开始.eg:range(5)等价于range(0,5) stop:计数到stop结束,但不包括stop.eg:range(0,5)是[0,1,2,3,4],没有5 step:步长,默认为1.eg:range(0,5)等价于range(0,5,1) 注意: 返回值:一个可迭代对象(类型是对象),不是列表,所以打印的时候不会打印列表list()函数式对象迭代器,可以把rang

uboot2011.09源代码ReadMe译文

# # (C) Copyright 2000 - 2011 # Wolfgang Denk, DENX Software Engineering, [email protected] #查看建立这个工程的文件列表人 # #这个程序是自由软件,你可以重新分配它或者修改它在GNU通用公共许可证以由自由软件基#金会发布:第二版或者任何之后的版本. #本程序是分布在希望它是有用的,但没有任何保证:甚至没有隐含保证. #查看 GNU通用公共许可证对于更多的细节. #你应该收到一份GNU通用公共许可证随着这