range-based for loop
是c++11
中引入的新的语法,例如:
// c++11
std::vector<int> arr {1, 2, 3, 4};
for (const auto &each : arr) {
std::cout << each << " ";
}
std::cout << std::endl;
// 输出
// 1 2 3 4
语法解释
for (range_declaration : range_expression) {
loop_statement
}
这个是range-based for loop
的语法,这个语法在c++11
、c++14
标准等同于
{
auto && __range = range_expression;
for (auto __begin = begin_expr, __end = end_expr; __begin != __end; ++_begin) {
range_declaration = *__begin;
loop_statement
}
}
在c++17
标准中等同于
{
auto && __range = range_expression;
auto __begin = begin_expr;
auto __end = end_expr;
for ( ; __begin != __end; ++__begin) {
range_declaration = *__begin;
loop_statement
}
}
range-based for loop解析的三个原则
如果
range_expression
为数组begin_expr = __range; end_expr = (__range + __bound)
其中,
__bound
是固定大小数组的长度(如果长度未知,则程序是有问题的,一般情况编译器会报错)如果
range_expression
是一个类,且这个类有名为begin
和end
的成员函数begin_expr = __range.begin(); end_expr = __range.end();
如果不满足上述要求,那么编译器会使用
ADL
查找符合条件的函数,如下所示begin_expr = begin(__range); end_expr = end(__range);
这里的begin函数和end函数可以在命名空间中,
ADL
都会找到匹配的函数
自定义类的range-based for loop
根据上面三个原则中的后两个,以及“语法解释”中C++扩展的代码可知,我们的自定义类Foo
需要实现
begin
和end
方法,这两个方法要么是Foo
的成员函数,要么这两个方法接受Foo
作为其参数根据“range-based for loop解析的三个原则”中的第二第三点
begin
和end
方法需要返回某各类,我们这里命名为FooInterator
,这个类需要实现!=
和++
的重载根据“语法解析”中,
__begin != __end
和++__begin
这两部分代码FooIterator
也可以是指针,指针原生支持!=
和++
运算符
例子
例子1
#include <iostream>
class IntArray3 {
public:
IntArray3() : arr_{1, 2, 3} {}
int* begin() { return arr_; }
int* end() { return arr_ + 3; }
private:
int arr_[3];
};
int main(int argc, char** argv) {
IntArray3 arr;
for (const auto &each : arr) {
std::cout << each << " ";
}
std::cout << std::endl;
return -1;
}
例子2
#include <iostream>
class IntArray3 {
public:
IntArray3() : arr_{1, 2, 3} {}
private:
int arr_[3];
friend int* begin(IntArray3 &arr);
friend int* end(IntArray3 &arr);
};
int* begin(IntArray3 &arr) {
return arr.arr_;
}
int* end(IntArray3 &arr) {
return arr.arr_ + 3;
}
int main(int argc, char** argv) {
IntArray3 arr;
for (const auto &each : arr) {
std::cout << each << " ";
}
std::cout << std::endl;
return -1;
}