C++20新特性_范围 (Ranges)

文章目录

  • [第一章 C++20核心语法特性](#第一章 C++20核心语法特性)

本文记录C++20新特性之范围 (Ranges)。

第一章 C++20核心语法特性

1.2 范围 (Ranges)

C++20引入了范围Range库,这是自C++11以来最大的一次现代化升级,可以让代码书写更简介,更符合现代化风格。

下面是C++11中容器的遍历方式,特点是传入两个迭代器,begin()和end().

cpp 复制代码
std::vector<int> v = {3, 1, 4};
std::sort(v.begin(), v.end()); // 必须写两次 v

在C++20中,实现上面的功能,使用了更简洁的方式。

1.2.1 Ranges定义

Ranges库包含在头文件 中,主要有以下几个概念。
范围(Ranges) : 任何可以提供begin() 和 end() 的东西都是Range, 例如,vector,std::array,C风格数组等。范围的引入让STL库中的算法更简洁,C++11给STL库传递开始和结束的迭代器,使用ranges只需要传递容器名称即可。
视图(View) : 视图是Ranges的精髓,视图主要的特点总结如下:

特点1:不拥有数据。可以把视图看成是指向原始数据的容器,类似于一个"智能指针",只是指向而不拥有,所以原始数据的生命周期结束,视图也会结束。

特点2:惰性求值。 这是视图最强大特性,操作多个视图时,不会立即执行计算,而是使用时才进行计算。

特点3:可组合。多个使用可以通过 管道符"|"进行组合。

**视图适配器:**用于生成View的工具,常用的视图适配器如下:

  • filter(pred) 筛选出满足谓词 pred 的元素。
  • transform(fn) 对每个元素应用函数 fn,并产生结果。
  • take(n) 获取范围中的前 n 个元素。
  • drop(n) 跳过范围中的前 n 个元素。
  • reverse 反转范围中元素的顺序。
  • keys 对于 map 或类似的关联容器,只获取键 (key)。
  • values 对于 map 或类似的关联容器,只获取值 (value)。
  • elements 对于元组 (tuple) 或 pair 的范围,只获取第 N 个元素。
  • iota(start, end) 生成一个从 start 到 end(不含)的数字序列。
  • join 将一个"范围的范围"扁平化为一个单一的范围。

1.2.2 使用说明

示例1:简化算法调用

下面例子可以明显看出,之前使用了迭代器方式进行遍历,现在直接传递容器即可。

cpp 复制代码
    void test()
    {
		std::vector<int> vec = { 1,2,3,4,5 };
        // C++11 的遍历方式
        std::for_each(vec.begin(), vec.end(), 
            [](int& n) {
            n *= 2;
            cout << n << " ";
         });
        cout << endl;
        // 2 4 6 8 10
        
        // C++20遍历方式
        std::ranges::for_each(vec, [](int& n) {
            n *= 2;
            cout << n << " ";
		});
        cout << endl;
		// 4 8 12 16 20
    }
示例2: 管道操作与试图组合

假设,对现在的数据过滤出偶数,取出前3个偶数后,进行反转。

cpp 复制代码
void test2()
 {
		std::vector<int> data = { 10,2,3,6,5,4,7,8,9,11 };

     // 过滤出偶数
     auto result1 = data 
| std::views::filter([](int n) { return n % 2 == 0; }); // 过滤偶数
     // C++20遍历方式
     std::ranges::for_each(result1, [](int& n) {
         cout << n << " ";
         });
     cout << endl;
     // 10 2 6 4 8

     // 使用管道符 操作
     auto result = data 
         | std::views::filter([](int n) { return n % 2 == 0; }) // 过滤偶数
| std::views::take(3) // 取前3个
| std::views::reverse; // 反转顺序

     // C++20遍历方式
     std::ranges::for_each(result, [](int& n) {
         cout << n << " ";
     });
     cout << endl;
     // 6 2 10
 }

总结:std::views::filter 传递一个 lambda表达式

示例3:过滤并修改map

下面例子展示了在map容器中使用视图适配器。

cpp 复制代码
void test()
 {
     std::map<std::string, int> scores = {
          {"Alice", 85}, {"Bob", 59}, {"Charlie", 92}, {"Dave", 40}
     };

     std::cout << "Passing students:\n";

     // 遍历 map,过滤分数 >= 60 的学生,并只获取他们的名字 (key)
     auto passers = scores
         | std::views::filter([](const auto& pair) { return pair.second >= 60; })
         | std::views::keys; // 专门用于 map 的视图,只取 key

     for (const auto& name : passers) {
         std::cout << "- " << name << "\n";
     }
 }
相关推荐
Mr_WangAndy7 小时前
C++20新特性_[[no_unique_address]]属性
c++20·c++20新特性·c++40周年
Mr_WangAndy9 小时前
C++20新特性_模块(Modules)
c++20·c++40周年·c++20新特性模块
Mr_WangAndy10 小时前
C++20新特性_范围 `for` 循环的初始化语句
c++20·c++40周年·范围for初始化
Mr_WangAndy11 小时前
C++20新特性_三路比较运算符 (<=>)
c++20·c++40周年·三路比较运算符
Mr_WangAndy11 小时前
C++20新特性_consteval 和 constinit
c++20·c++40周年·consteval·constinit
Azxcc012 小时前
c++20协程浅析
网络·c++20
Mr_WangAndy12 小时前
C++20新特性_协程(Coroutines)
c++20·c++20新特性·c++40周年·c++20协程
Mr_WangAndy12 小时前
C++20新特性_Lambda 改进
c++20·c++20新特性·c++40周年·lambda表达式改进
Mr_WangAndy21 小时前
C++17 新特性_第二章 C++17 语言特性_std::any和string_view
c++·string_view·c++40周年·c++17新特性·c++新特性any