使用基于范围的 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>{11235813};
4}
5
6std::multimap<intbool> getRates2()
7{
8    return std::multimap<intbool>{
9        {1true},
10        {1true},
11        {2false},
12        {3true},
13        {5true},
14        {8false},
15        {13true}
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 许可协议。转载请注明出处!

posted @ 2019-05-28 21:24  Lzl678  阅读(461)  评论(0编辑  收藏  举报