std::ranges::views::chunk_by 是按相邻元素二元谓词关系分组的视图,非固定长度切分;需传入 bool(t,t) 谓词,避免悬垂引用;返回 subgroup 为 subrange,仅含迭代器对,不拥数据、无 size() 或下标访问。

std::ranges::views::chunk_by 是什么,它不等于按固定大小切分
std::ranges::views::chunk_by 不是把容器切成等长块(那是 std::ranges::views::chunk 干的事),而是按**相邻元素的逻辑关系**做分组:只要相邻两个元素满足某个二元谓词(比如相等、同符号、同首字母),它们就被划进同一组;一旦谓词返回 false,就切出一个新组。
常见误用是把它当 chunk 用,结果发现分组长度完全不固定,甚至空输入也不报错——因为它的行为本质是“运行时扫描+状态累积”,不是索引切片。
必须传入二元谓词,且不能捕获局部变量导致悬垂引用
这个视图构造时必须显式提供一个可调用对象(函数指针、lambda、functor),类型为 bool(T, T)。最易踩的坑是写成带引用捕获的 lambda:
auto container = std::vector<int>{1,2,2,3,3,3};
auto key = 2;
auto view = container | std::views::chunk_by([&key](int a, int b) { return (a == key) == (b == key); });
// ❌ key 是栈变量,view 生命周期可能长于 key,访问未定义
</int>
正确做法包括:
- 用值捕获:
[key](int a, int b) { ... } - 用函数对象(无状态):
std::equal_to{}或自定义struct - 避免捕获,把逻辑提到外层计算好再传入
遍历 chunk_by 视图时,每个“块”是 std::ranges::subrange,不是 vector
你拿到的每个分组是 std::ranges::subrange<it></it>,它只保存迭代器对(begin/end),不拥有数据,也不支持 .size() 或随机访问。直接用 for (auto&& group : view) 是安全的,但别试图:
- 对
group调用std::size(group)(C++23 前不保证支持) - 写
group[0](除非你确认它是random_access_iterator且非空) - 把
group存起来等容器销毁后再用(迭代器失效)
安全用法示例:
for (auto&& group : container | std::views::chunk_by(std::equal_to{})) {
if (!group.empty()) {
std::cout <h3>和 std::ranges::views::chunk 混用需注意求值顺序与临时对象生命周期</h3><p>有人想先按逻辑分组、再对每组做固定切片,写成 <code>container | views::chunk_by(...) | views::chunk(N)</code> ——这在语法上合法,但语义危险:</p>
-
chunk_by输出的是惰性子范围,chunk会尝试把它们当序列处理,可能触发多次 begin()/end() 调用 - 若底层容器是临时对象(如函数返回的
vector),整个管道表达式结束前必须确保容器还活着 - 更稳妥的做法是先 materialize 分组(如用
std::vector<:vector>></:vector>收集),再对每个内层 vector 做chunk
真正需要链式视图时,请确认所有中间步骤都基于同一持久容器,且避免在 lambda 中隐式延长临时量生命期。
关键点始终是:chunk_by 的分组边界由运行时相邻比较决定,不是预分配内存;它轻量,但也因此对使用方式更敏感。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











