)
1.核心基础概念C20 正式引入范围库 (std::ranges)是对传统 STL 迭代器 算法体系的重大升级。它基于概念 (Concept)、范围 (Range)、视图 (View)、管道语法、投影 (Projection) 五大核心能力解决了传统 STL 写法繁琐、组合困难、易产生临时对象等问题实现线性链式调用、惰性求值、零开销视图。1.1.范围 (std::ranges::range)范围是满足 range 概念的类型只要类型拥有合法的 begin() 和 end()返回迭代器 / 哨兵就是一个范围。所有标准容器std::vector/std::string/std::map/ 数组天然是范围范围描述一个可遍历的元素序列不一定拥有实际数据。传统 STL 必须传 begin()/end()Ranges 算法直接接收整个范围写法大幅简化。C标准库之std::begin、std::end、std::pre和std::next1.2.哨兵 (Sentinel)C20 哨兵 (Sentinel) 是范围库 (Ranges) 引入的核心概念之一是对传统迭代器模型的重大泛化。它彻底改变了序列结束位置的表示方式允许迭代器与结束标记类型不同从而支持无界范围、自定义终止条件、优化边界判断等场景为现代 C 序列处理提供了极大灵活性。哨兵是标记范围 (Range) 结束位置的对象满足 std::sentinel_forI 概念其中 I 是对应的起始迭代器类型。它的核心作用是与迭代器进行相等性比较判断遍历是否结束而不必与迭代器是同一类型。C20 范围的定义一个对象只要提供 begin()返回迭代器和 end()返回哨兵且满足 sentinel_fordecltype(end()), decltype(begin())就是合法的范围。与传统迭代器的根本区别特性传统 STL 迭代器对C20 迭代器 哨兵类型要求begin() 和 end() 必须返回同类型迭代器end() 可返回任意类型哨兵只要满足 sentinel_for 概念结束判断迭代器相等比较迭代器与哨兵的自定义比较逻辑适用场景有限、已知边界的序列有限 / 无限序列、自定义终止条件、输入流等性能边界判断固定为指针比较可优化为更高效的判断逻辑如直接检查值核心概念sentinel_for 与 sized_sentinel_forstd::sentinel_forS, I核心约束要求 S 类型对象可与 I 类型迭代器比较operator判断是否到达序列末尾std::sized_sentinel_forS, I增强约束要求哨兵与迭代器之间可计算距离operator-支持 std::ranges::distance 等算法简化示例值边界哨兵更简洁的哨兵实现用于固定值边界判断12345678910111213141516171819202122232425#include ranges#include iostream// 边界哨兵当迭代器值等于bound时终止templatetypenameTstructBoundSentinel {T bound;// 比较函数迭代器值 边界值时终止friendbooloperator(constauto it,constBoundSentinel sentinel) {return*it sentinel.bound;}friendbooloperator!(constauto it,constBoundSentinel sentinel) {return!(it sentinel);}};intmain() {intarr[] {1, 2, 3, 4, 5, 0, 6, 7};// 0作为终止标记auto range std::ranges::subrange(std::begin(arr), BoundSentinelint{0});for(intx : range) {std::cout x ;// 输出 1 2 3 4 5}return0;}1.3.视图 (std::ranges::view)视图是 Ranges 最核心的组件也是和普通范围最大的区别轻量级、非拥有视图不拷贝、不持有原始数据仅对原有范围做 “遍历规则包装”廉价拷贝 / 移动拷贝视图几乎无开销惰性求值 (Lazy)仅在实际遍历时才计算元素链式组合不会产生中间临时容器不修改原数据所有视图都是只读变换。区分范围 序列本身视图 序列的 “透 视滤镜”。1.4.借用范围 (borrowed_range)用于保证临时范围可以被视图安全引用避免悬垂引用。例如 std::vector{1,2,3} | filter(...)临时容器生命周期会被视图合理托管。1.5.管道语法|Ranges 专属链式语法格式原始范围 | 适配器1 | 适配器2 | 适配器3等价于函数嵌套适配器3(适配器2(适配器1(原始范围)))从左到右依次执行代码线性可读。2.std::ranges 整体分类范围库全部位于 std::ranges 命名空间下分为四大模块范围算法对标传统 STL 算法增强参数、支持范围 / 投影视图适配器基于已有范围生成新视图过滤、变换、截取等视图工厂不依赖原有范围直接生成全新范围如连续数列范围概念模板约束range/view/input_range 等用于模板编程。3.范围算法std::ranges 算法3.1.语法差异形式1范围重载推荐日常首选传统 STL 算法必须传递首尾迭代器1std::sort(vec.begin(), vec.end());C20 Ranges 算法直接传入整个范围12345// 模板原型templatestd::ranges::input_range R, ...void算法名(R range, 其他参数...);std::ranges::sort(vec);形式2迭代器 哨兵重载兼容传统 / 自定义哨兵兼容旧式迭代器写法同时原生支持迭代器与哨兵类型不同C20 哨兵特性传统 STL 算法强制首尾迭代器同类型。123456789// 模板原型templatestd::input_iterator I, std::sentinel_forI S, ...void算法名(I first, S last, 其他参数...);// 示例传统迭代器 标准哨兵std::ranges::sort(vec.begin(), vec.end());// 示例迭代器 自定义哨兵C字符串auto cstr hello;std::ranges::for_each(cstr, std::default_sentinel, [](charc){});3.2.核心增强投影 (Projection)投影是一个可调用对象接收单个元素返回参与算法逻辑的值全程只读、不修改原数据。 专门用于提取结构体成员、计算衍生值大幅简化结构体 /std::pair 的排序、查找、统计逻辑。绝大多数 Ranges 算法新增投影参数用于提取元素的成员 / 属性替代繁琐的 Lambda是高频用法。语法规则通用1std::ranges::算法(范围, 谓词, 投影函数);投影函数接收单个元素返回用于比较 / 判断的值投影不会修改原元素仅做 “取值映射”。三种主流写法1.成员函数指针最常用结构体优先123structStudent { std::string name;intscore; };// 投影提取 score 成员std::ranges::sort(stus, std::ranges::less, Student::score);2.Lambda 表达式自定义计算 / 复杂取值12// 投影取元素绝对值参与比较std::ranges::sort(vec, std::ranges::less, [](intx){returnstd::abs(x); });3.普通函数 / 函数对象逻辑复用核心特点投影不修改原元素仅做「值映射」算法先执行投影再用投影结果做比较 / 判断所有谓词、比较器接收的都是投影后的值。