当前位置:   article > 正文

C++11 range-based for loop_use range-based for loop

use range-based for loop


很多编程语言都有基于范围的 for 循环(range-based for loop)语法功能。自 C++11 起,该基础功能被加入 C++ 标准。range-based for loop 语句,可以方便地遍历给定序列中的每个元素并对其执行某种操作。

1.语法

for(declaration:expression) {
    statements
}
  • 1
  • 2
  • 3

其中 declaration 定义一个变量,该变量将被用于访问序列中的基础元素,每次迭代,declaration 部分的变量会被初始化为 expression 部分的下一个元素值。expression 是一个对象,用于表示一个序列。statements 是对序列中元素的操作。

2.示例

vector<int> vec{1,2,3}; // C++11 only,大括号初始化
for (int v : vec) {
    cout << v;
}
// 输出结果:123
  • 1
  • 2
  • 3
  • 4
  • 5

上面的操作时将 vector 数组中的元素拷贝至变量 v 中进行输出。如果想改变 vector 数组中的元素值,需要把循环变量 v 定义成引用类型,实现如下:

vector<int> vec{1,2,3}; // C++11 only,大括号初始化  
for (auto& v : vec ) {
    v = v*v;
}
for (auto v : vec ) {
	cout << v;
}
// 输出结果:149
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

请注意,我们依然可以用 continue 语句来开始下一次迭代,使用 break 跳出循环,这一点和普通的 for 循环一样。

3.深入分析

range-based for loop 语句实际上等价于如下语句:

{
    auto && __range = expression ; 
    for (auto __begin = begin_expr, __end = end_expr; __begin != __end; ++__begin)
    { 
         auto v = *__begin; 
         loop_statement 
    } 
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

请注意,“等价于”并不表示编译器就是这么实现 range-based for loop,只是说两者的运行效果等价。其中 expression 是被迭代的对象, begin_expr 与 end_expr 是迭代对象的迭代器,取值有:
(1)对于数组类型 begin_expr 和 end_expr 分别等于__range__range + __bound
(2)对于 STL 中的容器,两者分别等于__range.begin()__range.end();
(3)对于其他类型,两者分别等于begin(__range)end(__range)。编译器将会通过参数类型找到合适的 begin 和 end 函数。

4.让自定义的类可以迭代

通过 range-based for loop 的等价语句可以看出,只要符合一定要求,自己定义的类也可以放在其中进行迭代。事实上要想进行迭代,一个类需要满足以下条件:
(1)拥有 begin 和 end 函数,返回值是一个可以自己定义的迭代器,分别指向第一个元素和最后一个元素。既可以是成员函数,也可以是非成员函数。
(2)迭代器本身支持 *、++、!= 运算符,既可以是成员函数,也可以是非成员函数。

示例如下:

#include <stdlib.h>
#include <iostream>  
using namespace std;

class IntVector {
	//迭代器类
	class Iter {
	public:
		Iter(IntVector* p_vec, int pos):_pos(pos),_p_vec(p_vec){}

		// these three methods form the basis of an iterator for use with 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
		{
			return _p_vec->get(_pos);
		}

		const Iter& operator++ ()
		{
			++_pos;
			return *this;
		}

	private:		
		IntVector *_p_vec;
		int _pos;
	};

public:
	IntVector(){}
	Iter begin(){
		return Iter(this,0);
	}
	Iter end(){
		return Iter(this, 20);
	}
	int& get(int col){
		return data[col];
	}
	void set(int index, int val){
		data[index] = val;
	}
private:
	int data[20] = {0};
};

int main() {
	IntVector v;
	for (int i = 0; i < 20; i++){
		v.set(i, i);
	}
	for (int& i : v) { i = i*i; cout << i <<" "; }
	system("pause");
}
  • 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
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59

程序输出结果:

0 1 4 9 16 25 36 49 64 81 100 121 144 169 196 225 256 289 324 361
  • 1

参考资料

Stanley B. Lippman等著,王刚,杨巨峰译.C++ Primer 中文第5版
Range-based for loop (since C++11)
C++11 新特性之Range-based for loops

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/795542
推荐阅读
相关标签
  

闽ICP备14008679号