C++20 —— Ranges

从一个例子说起

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
#include <iostream>
#include <ranges>

int main()
{
auto even = [](int x){return x % 2 == 0;};

for(int x = 1, count = 0; ;++x)
{
if(count == 10) break;
if(even(x))
{
std::cout << x << " ";
count++;
}
}

std::cout << "\n";

//利用Ranges
for(int num : std::views::take(std::views::filter(std::ranges::iota_view(1),even), 10))
{
std::cout << num << " ";
}
std::cout << "\n";


//利用管道操作符
for(int num: std::ranges::iota_view(1) | std::views::filter(even) | std::views::take(10))
{
std::cout << num << " ";
}
return 0;
}

Ranges的优势

image-20240611221542102

  • 从上一个例子可以看出,Ranges使得一些操作更简单

    • 去除后三个元素进行排序std::ranges::sort(std::views::drop(v, 3))
  • 可以减少一些手误的低级错误

  • 一些corner case更完善,写代码就没必要写一堆特判,这即带来了安全性也方便了使用者

    • 如我们希望从1 - 10倒着输出10个偶数,会发现结果只有四个,即8,6,4,2。

      代码:

      1
      2
      3
      4
      for(int num: std::ranges::iota_view(1, 10) | std::views::reverse | std::views::filter(even) | std::views::take(10))
      {
      std::cout << num << " ";
      }

一些概念

  • Ranges

    • is a concept, has begin(t) and end(t)

      1
      2
      3
      4
      5
      template<class T>
      concept range = requires(T& t){
      ranges::begin(t);
      ranges::end(t);
      }
    • array/set/list/vector/… STL容器 和 C数组 都是Ranges

  • Views

    • A view is a range

    • Created via Range Factories or Range Adaptors

    • 懒惰求值,这意味着在没用到之前不会计算,且计算是最小化,不会多计算。

    • 不拥有数据,但不是只读的!

      1
      2
      3
      4
      5
      std::vector vec{1, 2, 3, 4, 5, 6};
      auto v = std::views::reverse(vec);
      std::cout << *(v.begin() + 1) << "\n";//5
      *v.begin() = 0;
      for(int x: vec) std::cout << x << " ";// {1, 2, 3, 4, 5, 0}
  • Range Factories

    • Range Factories create Views
    • empty_view<int>e; static_assert(0 == e.size())
    • std::ranges::single_view : Create a view with a single element
      • single_view sv1 = 3.1415
      • std::string s = "hello world"; single_view sv2 = std::move(s)
    • std::ranges::iota_view
      • image-20240612002323270
  • Range Adaptors

    • 接受一个range,返回一个view
    • 主要配合管道操作符使用,摘自cppreference ”The ranges library includes range algorithms, which are applied to ranges eagerly, and range adaptors, which are applied to views lazily. Adaptors can be composed into pipelines, so that their actions take place as the view is iterated.“ 这告诉了我们管道操作符目前只能对返回view的Range Adaptors使用。
    • image-20240612002434978
  • Range Algorithms

一些存在的问题

  • 首先是ranges的相关内容命名很长,但可以通过using别名来解决
  • 用了using也会有一些命名空间上和std有冲突的命名,比如reverse

具体如下:

image-20240612003504593


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!