C++20 引入了 range 来简化对元素序列的解决(能够省略掉许多的循环遍历)。

1. range 和 view

range

range concept 通过提供一个迭代器以及一个哨兵来示意一个元素范畴,以容许对某个类型进行遍历。

template<class T>concept range = requires(T& t) {  ranges::begin(t);  ranges::end  (t);};

如,vector 就是一个 range:

std::vector<int> vec{ 1, 2, 3 };auto it1 = std::ranges::begin(vec);auto it2 = std::ranges::end(vec);

view

view 是一个 range,且具备常数工夫复杂度的的拷贝、挪动和赋值操作(如,间接操作一对迭代器、或应用生成器来按需生成元素)。

template<class T>concept view = ranges::range<T> && std::movable<T> && ranges::enable_view<T>;template<class T>inline constexpr bool enable_view =    std::derived_from<T, view_base> || /*is-derived-from-view-interface*/<T>;

如,可通过 iota 来创立一个 view,相似于 Python 中的 range:

auto v1 = std::views::iota(1);        // [1, +inf)auto v2 = std::views::iota(1, 10);    // [1, 10)for (int i : v2){    std::cout << i << ' ';}

2. 范畴工厂

会创立一个 view。

iota:创立一个一直递增的元素序列,能够是有界的,也能够是无界的。

#include <iostream>#include <ranges>int main(){    auto v1 = std::views::iota(10);        // [10, +inf)    auto v2 = std::views::iota(1, 10);     // [1, 10)    for (int i = 0; i < 10; i++)    {        std::cout << v1[i] << ' ';    }    std::cout << '\n';    for (int i : v2)    {        std::cout << i << ' ';    }}
10 11 12 13 14 15 16 17 18 191 2 3 4 5 6 7 8 9

istream_view:对某个输出流一直地利用 operator >>,从而取得一系列的元素。

#include <iostream>#include <sstream>#include <ranges>int main(){    std::istringstream nums("1.1 2.2 3.3\t4.4\n5.5");    auto v = std::ranges::istream_view<float>(nums);    for (float f : v)    {        std::cout << f << ", ";    }}
1.1, 2.2, 3.3, 4.4, 5.5,

3. 范畴适配器

承受一个 range,对其执行某些操作后,返回后果 view。

counted:从指定地位开始获取 n 个元素。

std::vector<int> vec{ 1, 2, 3, 4, 5, 6, 7 };for (int i : std::views::counted(vec.begin() + 1, 3)){    std::cout << i << ' ';}
2 3 4

drop:抛弃 range 中的前 n 个元素。

int nums[] = { 0, 1, 2, 3, 4, 5, 6 };for (int i : std::views::drop(nums, 3)){    std::cout << i << ' ';}
3 4 5 6

elements:获取第 n 列元素。

注:view 中的元素须要是 tuple-like 的。

std::vector<std::tuple<int, int, int>> vecs{    {1, 2, 3},    {4, 5, 6},    {7, 8, 9},};for (int i : std::views::elements<1>(vecs)){    std::cout << i << ' ';}
2 5 8

filter:对 range 进行过滤,只保留符合条件的元素。

int nums[] = { 0, 1, 2, 3, 4, 5 };auto even = [](int i){    return i % 2 == 0;};for (int i : std::views::filter(nums, even)){    std::cout << i << ' ';}
0 2 4

join:合并多个 range。

std::vector<int> vec1{ 1, 2, 3 };std::vector<int> vec2{ 4, 5, 6 };std::vector<std::vector<int>> vecs{vec1, vec2};for (int i : std::views::join(vecs)){    std::cout << i << ' ';}
1 2 3 4 5 6

reverse:反转 range 中的元素。

const int a[] = { 1, 2, 3, 4, 5, 6, 7 };for (int i : std::views::reverse(a)){    std::cout << i << ' ';}
7 6 5 4 3 2 1

split:按指定的元素宰割 range。

std::vector<int> vec{ 1, 2, 3, 4, 5, 6, 7 };for (const auto& v : std::views::split(vec, 4)){    for (int i : v)    {        std::cout << i << ' ';    }    std::cout << '\n';}
1 2 35 6 7

take:获取 range 中的前 n 个元素。

int nums[] = { 0, 1, 2, 3, 4, 5 };for (int i : std::views::take(nums, 3)){    std::cout << i << ' ';}
0 1 2

transform:对 range 中的每个元素执行指定的转换操作,转换操作的返回值就是后果 view 中的元素。

int nums[] = { 0, 1, 2, 3, 4, 5 };auto square = [](int i){    return i * i;};for (int i : std::views::transform(nums, square)){    std::cout << i << ' ';}
0 1 4 9 16 25

4. 管道运算符

如果 C 是一个范畴适配器闭包对象R 是一个能够转换为 view 的 range,则 C(R) 等价于 R | C

范畴适配器闭包对象包含:一元范畴适配器(只承受一个参数)、绑定了余下参数的多元范畴适配器(只留下第一个参数未指定)和 R | C 的返回值。

int nums[] = { 0, 1, 2, 3, 4, 5 };auto even = [](int i){    return i % 2 == 0;};auto square = [](int i){    return i * i;};// 先过滤,而后对过滤失去的元素求平方for (int i : nums | std::views::filter(even) | std::views::transform(square)){    std::cout << i << ' ';}
0 4 16