范围库 (C++20)

来自cppreference.com
< cpp
 
 
范围库
范围访问
范围转换器
(C++23)
范围原语



悬垂迭代器处理
范围概念
视图

范围工厂
适配器
范围生成器
范围适配器对象
范围适配器闭包对象
辅助项
 

范围库是一个对迭代器和泛型算法库的扩展,使得迭代器和算法可以通过组合变得更强大,并且减少错误。

范围库创造并操作范围视图,视图是一个代表可迭代对象(范围)的轻量对象。

范围是对区间的抽象


  • [beginend) – 迭代器对,例如可以从容器隐式获得范围。所有接受迭代器对的算法现在都有接受范围的重载(例如 ranges::sort
  • begin + [0size) – 有长度的序列,例如 views::counted 的结果
  • [beginpredicate) – 条件终止序列,例如 views::take_while 的结果
  • [begin..) – 未知边界序列,例如 views::iota 的结果

范围库包括受约束算法这些积极的算法,和范围适配器这些惰性的视图。适配器可以使用管道进行组合,以便于在视图迭代时应用。

在标头 <ranges> 定义
namespace std {

    namespace views = ranges::views;

}
(C++20 起)

提供命名空间别名 std::views ,作为 std::ranges::views 的缩写。

在命名空间 std::ranges 定义
范围访问
在标头 <ranges> 定义
在标头 <iterator> 定义
返回指向范围起始的迭代器
(定制点对象)
返回指示范围结尾的哨位
(定制点对象)
返回指向只读范围起始的迭代器
(定制点对象)
返回指示只读范围结尾的哨位
(定制点对象)
返回指向范围的逆向迭代器
(定制点对象)
返回指向范围的逆向尾迭代器
(定制点对象)
返回指向只读范围的逆向迭代器
(定制点对象)
返回指向只读范围的逆向尾迭代器
(定制点对象)
返回等于范围大小的整数
(定制点对象)
返回等于范围大小的有符号整数
(定制点对象)
检查范围是否为空
(定制点对象)
获得指向连续范围的起始的指针
(定制点对象)
获得指向只读连续范围的起始的指针
(定制点对象)
范围原语
在标头 <ranges> 定义
获取关联的范围类型
(别名模板)
悬垂迭代器处理
在标头 <ranges> 定义
占位类型,指示不应返回迭代器或子范围,因为它可能悬垂
(类)
获得塑造 borrowed_range 的迭代器类型或子范围类型
(别名模板)
范围概念
在标头 <ranges> 定义
指定类型为范围,即它同时提供 begin 迭代器和 end 哨位
(概念)
指定类型为 range 而且能安全返回从该类型表达式获得的迭代器而无悬垂之虞
(概念)
指定类型为可在常数时间内知晓大小的范围
(概念)
指定范围为视图,即它拥有常数时间的复制/移动/赋值
(概念)
指定范围的迭代器类型满足 input_iterator
(概念)
指定范围的迭代器类型满足 output_iterator
(概念)
指定范围的迭代器类型满足 forward_iterator
(概念)
指定范围的迭代器类型满足 bidirectional_iterator
(概念)
指定范围的迭代器类型满足 random_access_iterator
(概念)
指定范围的迭代器类型满足 contiguous_iterator
(概念)
指定范围拥有相同的迭代器和哨位类型
(概念)
指定针对 range 的要求,令其可安全转换为 view
(概念)
指定范围的所有元素只读
(概念)
范围转换器
在标头 <ranges> 定义
从另一范围构造一个非视图范围
(函数模板)
视图
在标头 <ranges> 定义
用于定义 view 的辅助类模板,使用奇特重现模板模式
(类模板)
将迭代器/哨位对结合为一个 view
(类模板)

范围工厂

在标头 <ranges> 定义
在命名空间 std::ranges 定义
无元素的空 view
(类模板) (变量模板)
含有具有指定值的单个元素的 view
(类模板) (定制点对象)
由通过重复对某个初值自增所生成的序列组成的 view
(类模板) (定制点对象)
由在关联的输入流上相继应用 operator>> 获得的元素组成的 view
(类模板) (定制点对象)
由重复产出同一值生成的序列组成的 view
(类模板) (定制点对象)
n 元笛卡尔积计算后的的元组组成的 view
(类模板) (定制点对象)

范围适配器

在标头 <ranges> 定义
在命名空间 std::ranges 定义
用于定义范围适配器闭包对象的辅助基类模板
(类模板)
包含 range 的所有元素的 view
(别名模板) (范围适配器对象)
某个其他 range 的元素的 view
(类模板)
拥有某 range 的独占所有权的 view
(类模板)
range 中满足某个谓词的元素构成的 view
(类模板) (范围适配器对象)
对序列的每个元素应用某个变换函数的 view
(类模板) (范围适配器对象)
由另一 view 的前 N 个元素组成的 view
(类模板) (范围适配器对象)
由另一 view 的到首个谓词返回 false 为止的起始元素组成的 view
(类模板) (范围适配器对象)
由另一 view 跳过首 N 个元素组成的 view
(类模板) (范围适配器对象)
由另一 view 跳过元素的起始序列,直至首个谓词返回 false 的元素组成的 view
(类模板) (范围适配器对象)
由拉平 range 组成的 view 所获得的序列构成的 view
(类模板) (范围适配器对象)
用某个分隔符切割另一 view 所获得的子范围的 view
(类模板) (范围适配器对象)
用某个分隔符切割另一 view 所获得的子范围的 view
(类模板) (范围适配器对象)
从迭代器和计数创建子范围
(定制点对象)
转换 viewcommon_range
(类模板) (范围适配器对象)
以逆序迭代另一双向视图上的元素的 view
(类模板) (范围适配器对象)
选取 tuple-like 值组成的 view 和数值 N,产生每个 tuple 的第 N 个元素的 view
(类模板) (范围适配器对象)
选取 pair 式值组成的 view 并产生每个 pair 的第一元素的 view
(类模板) (范围适配器对象)
选取 pair 式值组成的 view 并产生每个 pair 的第二元素的 view
(类模板) (范围适配器对象)
到被适配视图的对应元素的位置和他的值组成的元组的 view
(类模板) (范围适配器对象)
到被适配视图的对应元素的引用元组组成的 view
(类模板) (定制点对象)
由应用变换函数到被适配视图的对应元素的结果的元组组成的 view
(类模板) (定制点对象)
由到被适配视图的相邻元素的引用的元组组成的 view
(类模板) (范围适配器对象)
由应用变换函数到被适配视图的相邻元素的结果的元组组成的 view
(类模板) (范围适配器对象)
由拉平范围组成的视图并以分隔符间隔所获得的序列构成的 view
(类模板) (范围适配器对象)
第 M 个元素是另一 view 从第 M 到第 (M + N - 1) 个元素的 view 构成的 view
(类模板) (范围适配器对象)
另一个视图元素的 N 大小不重叠的连续块组成的 view 的范围
(类模板) (范围适配器对象)
当给定的谓词返回 false 的时候,将 view 分割成每一对临近元素的子范围
(类模板) (范围适配器对象)
转换 viewconstant_range
(类模板) (范围适配器对象)
由将序列所有元素转换为右值组成的 view
(类模板) (范围适配器对象)
由另一 view 的元素每次前进 N 步所获得的 view
(类模板) (范围适配器对象)

范围生成器

在标头 <generator> 定义
在命名空间 std 定义
(C++23)
表示同步协程生成器的 view
(类模板)

辅助项

范围适配器对象

范围适配器对象 (RangeAdaptorObject)

范围适配器闭包对象

范围适配器闭包对象 (RangeAdaptorClosureObject)

定制点对象

定制点对象

可复制的包装器

某些范围适配器使用 可拷贝包装 (C++23 前)可移动包装 (C++23 起) 包装其元素或函数对象。必要时,包装器会增强被包装对象的可分配性。

非传播缓存

某些范围适配器是通过 非传播缓存 这一仅用于阐述的类模板指定的,其行为几乎与 std::optional<T> 完全相同(不同之处请参见说明)。

定制点对象辅助模板

template< ranges::input_range R >

constexpr auto& /*possibly-const-range*/(R& r) {
  if constexpr (ranges::constant_range<const R> && !ranges::constant_range<R>) {
    return const_cast<const R&>(r);
  } else {
    return r;
  }

}
(1) (仅用于阐述*)
template< class T >

constexpr auto /*as-const-pointer*/( const T* p ) {
  return p;

}
(2) (仅用于阐述*)

某些范围访问自定义点对象是根据这些仅用于阐述的函数模板指定的。

1) /*possibly-const-range*/ 在是 deep-const range 时返回 const-qualified range r;否则,不进行任何转换,返回 r
2) /*as-const-pointer*/ 返回常量类型对象的指针。

范围适配器辅助模板

template< class F, class Tuple >

constexpr auto /*tuple-transform*/( F&& f, Tuple&& tuple ) {
  return std::apply([&]<class... Ts>(Ts&&... elements) {
    return std::tuple<std::invoke_result_t<F&, Ts>...>(
      std::invoke(f, std::forward<Ts>(elements))...
    );
  }, std::forward<Tuple>(tuple));

}
(1) (仅用于阐述*)
template< class F, class Tuple >

constexpr void /*tuple-for-each*/( F&& f, Tuple&& tuple ) {
  std::apply([&]<class... Ts>(Ts&&... elements) {
    (static_cast<void>(std::invoke(f, std::forward<Ts>(elements))), ...);
  }, std::forward<Tuple>(tuple));

}
(2) (仅用于阐述*)
template< class T >

constexpr T& /*as-lvalue*/( T&& t ) {
  return static_cast<T&>(t);

}
(3) (仅用于阐述*)

有些量程适配器是用这些仅用于阐述的函数模板指定的。

1) /*tuple-transform*/ 返回对 tuple 的每个元素应用 f 的新 tuple
2) /*tuple-for-each*/tuple 的每个元素应用 f 然后什么都不返回。
3) /*as-lvalue*/ 转发右值 t 为左值。

辅助概念

以下仅用于阐述的概念用于几种类型,但它们不是标准库接口的一部分。

template< class R >

  concept /*simple-view*/ =
    ranges::view<R> && ranges::range<const R> &&
    std::same_as<ranges::iterator_t<R>, ranges::iterator_t<const R>> &&

    std::same_as<ranges::sentinel_t<R>, ranges::sentinel_t<const R>>;
(1) (仅用于阐述*)
template< class I >

  concept /*has-arrow*/ =
    ranges::input_iterator<I> &&

    (std::is_pointer_v<I> || requires(I i) { i.operator->(); });
(2) (仅用于阐述*)
template< class T, class U >

  concept /*different-from*/ =

    !std::same_as<std::remove_cvref_t<T>, std::remove_cvref_t<U>>;
(3) (仅用于阐述*)
template< class R >

  concept /*range-with-movable-references*/ =
    ranges::input_range<R> &&
    std::move_constructible<ranges::range_reference_t<R>> &&

    std::move_constructible<ranges::range_rvalue_reference_t<R>>;
(4) (仅用于阐述*)

注解

功能特性测试 标准 注释
__cpp_lib_generator 202207L (C++23) std::generator – 适用于范围的同步协程生成器
__cpp_lib_ranges 201911L (C++20) 范围库受约束算法
202106L (C++20)
(DR)
默认可初始化 视图
202110L (C++20)
(DR)
所有权视图
202202L (C++23) std::ranges::range_adaptor_closure
202207L (C++23) 放松范围适配器以允许仅移动类型
202211L (C++23) 移除 “毒药丸” (P2602)ranges::begin 等的重载
__cpp_lib_ranges_as_const 202207L (C++23) std::const_iterator, std::ranges::as_const_view
__cpp_lib_ranges_as_rvalue 202207L (C++23) std::ranges::as_rvalue_view
__cpp_lib_ranges_cartesian_product 202207L (C++23) std::ranges::cartesian_product_view
__cpp_lib_ranges_chunk 202202L (C++23) std::ranges::chunk_view
__cpp_lib_ranges_chunk_by 202202L (C++23) std::ranges::chunk_by_view
__cpp_lib_ranges_enumerate 202302L (C++23) std::ranges::enumerate_view
__cpp_lib_ranges_join_with 202202L (C++23) std::ranges::join_with_view
__cpp_lib_ranges_repeat 202207L (C++23) std::ranges::repeat_view
__cpp_lib_ranges_slide 202202L (C++23) std::ranges::slide_view
__cpp_lib_ranges_stride 202207L (C++23) std::ranges::stride_view
__cpp_lib_ranges_to_container 202202L (C++23) std::ranges::to
__cpp_lib_ranges_zip 202110L (C++23) std::ranges::zip_view,
std::ranges::zip_transform_view,
std::ranges::adjacent_view,
std::ranges::adjacent_transform_view


示例

#include <ranges>
#include <iostream>
 
int main()
{
    auto const ints = {0,1,2,3,4,5};
    auto even = [](int i) { return 0 == i % 2; };
    auto square = [](int i) { return i * i; };
 
    // 组合视图的“管道”语法:
    for (int i : ints | std::views::filter(even) | std::views::transform(square)) {
        std::cout << i << ' ';
    }
 
    std::cout << '\n';
 
    // 传统的“函数式”组合语法:
    for (int i : std::views::transform(std::views::filter(ints, even), square)) {
        std::cout << i << ' ';
    }
}

输出:

0 4 16


缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

缺陷报告 应用于 出版时的行为 正确行为
LWG 3509 C++20 不明确范围适配器对象如何绑定尾随参数 按值绑定它们