范围库 (C++20)

来自cppreference.com
< cpp


 
 
范围库
范围适配器
 

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

范围库创造并操作范围视图,它们是间接表示可遍历的序列(范围)的轻量对象。 范围是对以下内容的抽象:

  • [beginend) – 迭代器对,例如,范围可以从容器隐式转换而得。所有接受迭代器对的算法现在都有接受范围的重载(例如 ranges::sort
  • begin + [0size) – 计数的序列,例如 views::counted 返回的范围
  • [begin谓词) – 按条件终止的序列,例如 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> 定义
将范围标记为当作序列而非单个值对待
(类模板)
范围概念
在标头 <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
(类模板) (定制点对象)
由重复产出同一值生成的序列组成的 view
(类模板) (定制点对象)
由在关联的输入流上相继应用 operator>> 获得的元素组成的 view
(类模板) (定制点对象)

范围适配器

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

范围生成器

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

辅助项

范围适配器对象

范围适配器对象 (RangeAdaptorObject)

范围适配器闭包对象

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

定制点对象

定制点对象

可赋值的包装器

某些范围适配器使用 copyable-box (C++23 前)movable-box (C++23 起) 来包装它的元素或函数对象。必要时,包装器会以可赋值性增强被包装对象。

非传播缓存

某些范围适配器是通过 non-propagating-cache 这一仅用于阐述的类模板指定的,它的行为与 std::optional<T> 几乎相同(不同之处请参见说明)。

条件性 const 类型

template< bool Const, class T >
using /*maybe-const*/ = std::conditional_t<Const, const T, T>;
(仅用于阐述*)

别名模板 /*maybe-const*/ 是用于为类型 T 有条件应用 const 限定的便利方式。

整数式类型辅助模板

template< /*is-integer-like*/ T >
using /*make-signed-like-t*/<T> = /* 见描述 */;
(1) (仅用于阐述*)
template< /*is-integer-like*/ T >
using /*make-unsigned-like-t*/<T> = /* 见描述 */;
(2) (仅用于阐述*)
template< /*is-integer-like*/ T >

/*make-unsigned-like-t*/<T> /*to-unsigned-like*/( T t )
{
    return static_cast</*make-unsigned-like-t*/<T>>(t);

}
(3) (仅用于阐述*)
1) 对于整数式类型 T
  • 如果 T 是整数类型,那么 /*make-signed-like-t*/<T>std::make_signed_t<T>
  • 否则,/*make-signed-like-t*/<T> 是一个与 T 的宽度相同的对应未指定有符号整数式类型。
2) 对于整数式类型 T
  • 如果 T 是整数类型,那么 /*make-unsigned-like-t*/<T>std::make_unsigned_t<T>
  • 否则,/*make-signed-like-t*/<T> 是一个与 T 的宽度相同的对应未指定无符号整数式类型。
3)t 显式转换到 /*make-unsigned-like-t*/<T>

定制点对象辅助模板

template< ranges::input_range R >

constexpr auto& /*possibly-const-range*/(R& r) noexcept
{
    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 ) noexcept
{
    return p;

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

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

1) /*possibly-const-range*/ 在是深 const 范围时返回 const 限定的范围 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&&... args)
    {
        return std::tuple<std::invoke_result_t<F&, Ts>...>
            (std::invoke(f, std::forward<Ts>(args))...);
    }, std::forward<Tuple>(tuple));

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

constexpr void /*tuple-for-each*/( F&& f, Tuple&& tuple )
{
    std::apply([&]<class... Ts>(Ts&&... args)
    {
        (static_cast<void>(std::invoke(f, std::forward<Ts>(args))), ...);
    }, 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) (仅用于阐述*)
template< bool C, class... Views >

concept /*all-random-access*/ =
    (ranges::random_access_range

         <std::conditional_t<C, const Views, Views>> && ...);
(5) (仅用于阐述*)
template< bool C, class... Views >

concept /*all-bidirectional*/ =
    (ranges::bidirectional_range

         <std::conditional_t<C, const Views, Views>> && ...);
(6) (仅用于阐述*)
template< bool C, class... Views >

concept /*all-forward*/ =

    (ranges::forward_range<std::conditional_t<C, const Views, Views>> && ...);
(7) (仅用于阐述*)

注解

功能特性测试 标准 功能特性
__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) ranges::range_adaptor_closure
202207L (C++23) 放松范围适配器以允许仅移动类型
202211L (C++23) 移除 “毒药丸” (P2602)ranges::begin 等的重载
202302L (C++23) 放宽范围限制已允许使用某些投影
202406L (C++20)
(DR)
从间接调用概念中移除公共引用要求
__cpp_lib_ranges_as_const 202207L (C++23) std::const_iteratorranges::as_const_view
__cpp_lib_ranges_as_rvalue 202207L (C++23) ranges::as_rvalue_view
__cpp_lib_ranges_cartesian_product 202207L (C++23) ranges::cartesian_product_view
__cpp_lib_ranges_chunk 202202L (C++23) ranges::chunk_view
__cpp_lib_ranges_chunk_by 202202L (C++23) ranges::chunk_by_view
__cpp_lib_ranges_concat 202403L (C++26) ranges::concat_view
__cpp_lib_ranges_enumerate 202302L (C++23) ranges::enumerate_view
__cpp_lib_ranges_join_with 202202L (C++23) ranges::join_with_view
__cpp_lib_ranges_repeat 202207L (C++23) ranges::repeat_view
__cpp_lib_ranges_slide 202202L (C++23) ranges::slide_view
__cpp_lib_ranges_stride 202207L (C++23) ranges::stride_view
__cpp_lib_ranges_to_container 202202L (C++23) ranges::to
__cpp_lib_ranges_zip 202110L (C++23) ranges::zip_view,
ranges::zip_transform_view,
ranges::adjacent_view,
ranges::adjacent_transform_view


示例

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

缺陷报告

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

缺陷报告 应用于 出版时的行为 正确行为
LWG 3509
(P2281R1)
C++20 不明确范围适配器对象如何绑定尾随参数 按值绑定它们
LWG 3948 C++23 possibly-const-rangeas-const-pointer 没有声明 noexcept 声明 noexcept

参阅