使用基于范围的 for 循环迭代范围
特别声明:
本文翻译自 Modern C++ Programming Cookbook 一书中的“Learning Modern Core Language Features”章节中的“Using range-based for loops to iterate on a range”小节。
翻译此文纯粹作为学习之用,版权归原作者及出版社所有。
许多编程语言支持 for 循环的称之为 for each 的变体,即针对集合中的元素重复一组语句。在 C++11 之前 C++没有相应的核心语言支持。最接近的特性是来自标准库中的被称为 std::for_each 的通用算法,它在范围的所有元素上应用一个函数。C++11 带来了对 for each 的语言级支持,实际称之为基于范围 for 循环。新的 C++17 标准对原始语言特性提供了一些改进。
Getting ready
在 C++11 中,基于范围 for 循环的通用语法如下:
1for (range_declaration : range_expression) loop_statement
为了举例说明基于范围的 for 循环的不同用法,我们将使用下面这些函数返回元素序列:
1std::vector<int> getRates()
2{
3 return std::vector<int>{1, 1, 2, 3, 5, 8, 13};
4}
5
6std::multimap<int, bool> getRates2()
7{
8 return std::multimap<int, bool>{
9 {1, true},
10 {1, true},
11 {2, false},
12 {3, true},
13 {5, true},
14 {8, false},
15 {13, true}
16 };
17}
How to do it…
基于范围的 for 循环可以通过不同的方式使用:
- 为序列元素提供一个特定类型:
1auto rates = getRates();
2for (int rate : rates)
3 std::cout << rate << std::endl;
4
5for (int &rate : rates)
6 rate *= 2;
- 不指定类型并由编译器进行推导:
1for (auto &&rate : getRates())
2 std::cout << rate << std::endl;
3
4for (auto &rate : rates)
5 rate *= 2;
6
7for (auto const &rate : rates)
8 std::cout << rate << std::endl;
- 在 C++17 中,通过使用结构化绑定和解构声明:
1for (auto &&[rate, flag] : getRates2())
2 std::cout << rate << std::endl;
How it works…
之前在 How to do it… 中显示的基于范围的 for 循环的表达式是基础的语法糖,编译器会将其转换为其它的东西。在 C++17 之前,编译器生成的代码如下所示:
1{
2 auto &&__range = range_expression;
3 for (auto __begin = begin_expr, __end = end_expr;
4 __begin != __end; ++__begin)
5 {
6 range_declaration = *__begin;
7 loop_statement
8 }
9}
代码中的 begin_expr 和 end_expr 依赖于这个范围的类型:
- 对于 C 风格的数组,__range 和 __bound 是数组中元素的个数。
- 对于有 begin() 和 end() 成员的类类型(无论它们的类型和可访问性):__range.begin() 和 __range.end()。
- 对于其它类型是 begin(__range) 和 end(__range),通过参数依赖查找进行确定。
需要注意的是,如果一个类包含名为 begin 或 end 的任何成员(函数,数据成员或枚举器),无论它们的类型和可访问性,它们都将被选为 begin_expr 和 end_expr。因此,这样的类类型不能使用基于范围 for 循环。
在 C++17 中,编译器生成的代码略微不同:
1{
2 auto &&__range = range_expression;
3 auto __begin = begin_expr;
4 auto __end = end_expr;
5 for (; __begin != __end; ++__begin)
6 {
7 range_declaration = *__begin;
8 loop_statement
9 }
10}
新标准移除了 begin 表达式和 end 表达式必须拥有同一类型的约束。end 表达式不再需要是一个实际的迭代器,但是它必须能够与迭代器进行不等式比较。
这样做的好处是范围可以由谓词分隔。
See also
- 为自定义类型启用基于范围的 for 循环
- - - End - - -
本文作者: Lzl678
本文链接: https://www.cnblogs.com/Lzl678/p/10940182.html
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!