范围库 (C++20)
范围库是一个对迭代器和泛型算法库的扩展,使得迭代器和算法可以通过组合变得更强大,并且减少错误。
范围库创造并操作范围视图,视图是一个代表可迭代对象(范围)的轻量对象。
范围是对区间的抽象
- [begin, end) 迭代器对,例如可以从容器隐式获得范围。所有接受迭代器对的算法现在都有接受范围的重载(例如 ranges::sort)
- [start, size) 有长度的序列,例如 views::counted 的结果
- [start, predicate) 条件终止序列,例如 views::take_while 的结果
- [start..) 未知边界序列,例如 views::iota 的结果
范围库包括 range algorithms 这些积极的算法,和 range adaptors 这些惰性的视图。适配器可以使用管道进行组合,以便于在视图迭代时应用。
| 在标头  <ranges>定义 | ||
| namespace std {     namespace views = ranges::views; | (C++20 起) | |
提供命名空间别名 std::views ,作为 std::ranges::views 的缩写。
| 定义于命名空间  std::ranges | |
| 范围访问 | |
| 定义于头文件  <ranges> | |
| 定义于头文件  <iterator> | |
| (C++20) | 返回指向范围起始的迭代器 (定制点对象) | 
| (C++20) | 返回指示范围结尾的哨位 (定制点对象) | 
| (C++20) | 返回指向只读范围起始的迭代器 (定制点对象) | 
| (C++20) | 返回指示只读范围结尾的哨位 (定制点对象) | 
| (C++20) | 返回指向范围的逆向迭代器 (定制点对象) | 
| (C++20) | 返回指向范围的逆向尾迭代器 (定制点对象) | 
| (C++20) | 返回指向只读范围的逆向迭代器 (定制点对象) | 
| (C++20) | 返回指向只读范围的逆向尾迭代器 (定制点对象) | 
| (C++20) | 返回等于范围大小的整数 (定制点对象) | 
| (C++20) | 返回等于范围大小的有符号整数 (定制点对象) | 
| (C++20) | 检查范围是否为空 (定制点对象) | 
| (C++20) | 获得指向连续范围的起始的指针 (定制点对象) | 
| (C++20) | 获得指向只读连续范围的起始的指针 (定制点对象) | 
| 范围原语 | |
| 定义于头文件  <ranges> | |
| 获得范围的关联类型 (别名模板) | |
| 悬垂迭代器处理 | |
| 定义于头文件  <ranges> | |
| (C++20) | 占位类型,指示不应返回迭代器或子范围,因为它可能悬垂 (类) | 
| 获得塑造 borrowed_range的迭代器类型或子范围类型(别名模板) | |
| 范围概念 | |
| 定义于头文件  <ranges> | |
| (C++20) | 指定类型为范围,即它同时提供 begin迭代器和end哨位(概念) | 
| (C++20) | 指定类型为 range而且能安全返回从该类型表达式获得的迭代器而无悬垂之虞(概念) | 
| (C++20) | 指定范围可在常数时间内知晓其大小 (概念) | 
| (C++20) | 指定范围为视图,即它拥有常数时间的复制/移动/赋值 (概念) | 
| (C++20) | 指定范围的迭代器类型满足 input_iterator(概念) | 
| (C++20) | 指定范围的迭代器类型满足 output_iterator(概念) | 
| (C++20) | 指定范围的迭代器类型满足 forward_iterator(概念) | 
| (C++20) | 指定范围的迭代器类型满足 bidirectional_iterator(概念) | 
| (C++20) | 指定范围的迭代器类型满足 random_access_iterator(概念) | 
| (C++20) | 指定范围的迭代器类型满足 contiguous_iterator(概念) | 
| (C++20) | 指定范围拥有相同的迭代器和哨位类型 (概念) | 
| (C++20) | 指定针对 range的要求,令其可安全转换为view(概念) | 
| (C++23) | 指定范围的所有元素只读 (概念) | 
| 转换器 | |
| 定义于头文件  <ranges> | |
| (C++23) | 从另一范围构造一个非视图范围 (函数模板) | 
| 视图 | |
| 定义于头文件  <ranges> | |
| (C++20) | 用于定义 view的辅助类模板,使用奇异递归模板模式(类模板) | 
| (C++20) | 将迭代器/哨位对结合为一个 view(类模板) | 
范围工厂
| 定义于头文件  <ranges> | |
| 定义于命名空间  std::ranges | |
| 无元素的空 view(类模板) (变量模板) | |
| 含有具有指定值的单个元素的 view(类模板) (定制点对象) | |
| (C++20) | 由通过重复对某个初值自增所生成的序列组成的 view(类模板) (定制点对象) | 
| 由在关联的输入流上相继应用 operator>>获得的元素组成的view(类模板) (定制点对象) | |
| 由重复产出同一值生成的序列组成的 view(类模板) (定制点对象) | |
| n 元笛卡尔积计算后的的元组组成的 view(类模板) (定制点对象) | |
范围适配器
| 定义于头文件  <ranges> | |
| 定义于命名空间  std::ranges | |
| (C++20) | 包含 range的所有元素的view(别名模板) (范围适配器对象) | 
| (C++20) | 某个其他 range的元素的view(类模板) | 
| (C++20) | 拥有某 range的独占所有权的view(类模板) | 
| 由 range中满足某个谓词的元素构成的view(类模板) (范围适配器对象) | |
| 对序列的每个元素应用某个变换函数的 view(类模板) (范围适配器对象) | |
| (C++20) | 由另一 view的前 N 个元素组成的view(类模板) (范围适配器对象) | 
| 由另一 view的到首个谓词返回false为止的起始元素组成的view(类模板) (范围适配器对象) | |
| (C++20) | 由另一 view跳过首 N 个元素组成的view(类模板) (范围适配器对象) | 
| 由另一 view跳过元素的起始序列,直至首个谓词返回false的元素组成的view(类模板) (范围适配器对象) | |
| (C++20) | 由拉平 range组成的view所获得的序列构成的view(类模板) (范围适配器对象) | 
| 用某个分隔符切割另一 view所获得的子范围的view(类模板) (范围适配器对象) | |
| 用某个分隔符切割另一 view所获得的子范围的view(类模板) (范围适配器对象) | |
| (C++20) | 从迭代器和计数创建子范围 (定制点对象) | 
| 转换 view为common_range(类模板) (范围适配器对象) | |
| 以逆序迭代另一双向视图上的元素的 view(类模板) (范围适配器对象) | |
| 选取元组式值组成的 view和数值 N ,产生每个 tuple 的第 N 个元素的view(类模板) (范围适配器对象) | |
| (C++20) | 选取 pair 式值组成的 view并产生每个 pair 的第一元素的view(类模板) (范围适配器对象) | 
| 选取 pair 式值组成的 view并产生每个 pair 的第二元素的view(类模板) (范围适配器对象) | |
| (C++23) | 到被适配视图的对应元素的引用元组组成的 view(类模板) (定制点对象) | 
| 由应用变换函数到被适配视图的对应元素的结果的元组组成的 view(类模板) (定制点对象) | |
| 由到被适配视图的相邻元素的引用的元组组成的 view(类模板) (范围适配器对象) | |
| 由应用变换函数到被适配视图的相邻元素的结果的元组组成的 view(类模板) (范围适配器对象) | |
| 由拉平范围组成的视图并以分隔符间隔所获得的序列构成的 view(类模板) (范围适配器对象) | |
| a viewwhose Mth element is aviewover the Mth through (M + N - 1)th elements of anotherview(类模板) (范围适配器对象) | |
| 另一个视图元素的 N 大小不重叠的连续块组成的 view的范围(类模板) (范围适配器对象) | |
| 当给定的谓词返回 false 的时候,将 view分割成每一对临近元素的子范围(类模板) (范围适配器对象) | |
| converts a viewinto a [[cpp/未识别的概念/constant_range|constant_range]](类模板) (范围适配器对象) | |
| 由将序列所有元素转换为右值组成的 view(类模板) (范围适配器对象) | |
| a viewconsisting of elements of anotherview, advancing over N elements at a time(类模板) (范围适配器对象) | |
某些范围适配器用可复制包装包装其元素或函数对象。
范围适配器对象
范围适配器对象是接收 viewable_range 作为其首参数并返回 view 的定制点对象。一些范围适配器对象是一元的,即它们接收一个 viewable_range 作为其仅有的参数。其他范围适配器对象接收一个 viewable_range 和其他尾随参数。
若范围适配器接收多于一个参数,则它亦支持部分应用:令
-  a为范围适配器对象,而
- args... 为参数(通常适合作为尾随参数),
则表达式 a(args...) 拥有下列属性:
-  它合法当且仅当对每个 args... 中的 e ,设 E为 decltype((e)) , std::is_constructible_v<std::decay_t<E>, E> 为 true ,
- 当调用合法时,其结果对象对每个 e 中的 args... 存储以 std::forward<E>(e) 直接非列表初始化的 std::decay_t<E> 类型子对象,而且
- 结果对象是范围适配器闭包对象(见后述)。
类似其他定制点对象,令
-  a为任何范围适配器类型的 cv 无限定版本的对象,
-  args... 任何满足 a的 operator() 的约束参数组,
对
- a(args...)、
- std::as_const(a)(args...)、
- std::move(a)(args...) 及
- std::move(std::as_const(a))(args...)
的调用全部等价。
每个这些表达式的结果对象是一个 view 对象或范围适配器闭包对象。
注:范围适配器类型的 volatile 限定或 const-volatile 限定版本不支持 operator() 。数组和函数在绑定时转换成指针。
范围适配器闭包对象
范围适配器闭包对象是类型同下列对象之一(忽略 cv 限定)的对象:
- 一元范围适配器对象、
- 范围适配器对象绑定尾随参数的结果,及
- operator| 连接两个范围适配器闭包对象的结果。
范围适配器对象接收一个 viewable_range 作为其仅有的参数并返回 view 。它们可通过管道运算符调用:若 C 是范围适配器闭包对象且 R 为 viewable_range ,则下列两个表达式等价(均为良构或非良构):
C(R) R | C
此调用将绑定的参数(若存在)转发给关联的范围适配器对象。绑定的参数(若存在)被当作与 C 等同地为左值或右值以及具有 cv 限定。
两个范围适配器闭包对象能由 operator| 连接以产生另一个范围适配器闭包对象:若 C 与 D 为范围适配器闭包对象,则 C | D 亦为范围适配器闭包对象,若它合法。
C | D 的绑定参数确定如下:
- 对两个操作数中的每个作为绑定参数的子对象,结果对象中有一个同类型子对象(舍弃 cv 限定),
- 这种绑定的参数以含有它的操作数中的源子对象直接非列表初始化,其中源被当作与操作数等同地为左值或右值以及具有 cv 限定,而且
- 结果合法当且仅当所有绑定参数的初始化为合法。
结果的 operator() 的效果与合法性确定如下:给定 viewable_range R ,这两个表达式等价(均为合法或非合法):
R | C | D // (R | C) | D R | (C | D)
注意:范围适配器闭包类型的 volatile 限定或 const-volatile 限定版本不支持 operator() 。
示例
#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 | 不明确范围适配器对象如何绑定尾随参数 | 按值绑定它们 |