chunk_by 是按相邻元素谓词结果变化点切分序列的视图,与传统按值分组的 group_by 不同;它接收双参数谓词判断是否“不切”,false 处切分,返回 subrange 序列,需注意生命周期和遍历方式。

chunk_by 是什么,它和 group_by 有什么区别?
std::ranges::views::chunk_by 不是按值分组,而是按**相邻元素的谓词结果变化点**切分序列。它不关心元素是否相等,只看相邻两个元素传给谓词后返回值是否不同——一旦 pred(a, b) 为 false(即“断开”),就在此处切一刀。
这和传统意义上的“分组相同元素”(比如 group_by)容易混淆。C++23 标准库至今没有 group_by,只有 chunk_by;如果你想要按值归类,得自己用 std::ranges::views::adjacent_remove_if 或配合 std::ranges::views::scan 模拟,但那不是 chunk_by 的职责。
- ✅ 正确场景:按状态切换切分日志行(如从 "INFO" 切到 "ERROR")、按单调性变化分段(升序→降序)、按 flag 开关分割数据块
- ❌ 错误预期:想把
{1,2,2,3,3,3}变成{{1},{2,2},{3,3,3}}—— 这需要相邻相等判断,但chunk_by的谓词接收的是**两个相邻元素**,不是单个元素
怎么写一个合法的 chunk_by 谓词?
chunk_by 要求谓词签名必须是 bool(auto&&, auto&&),且作用于**连续两个元素**(左、右),返回 true 表示“属于同一 chunk”,false 表示“此处断开”。注意:返回 true 并不意味着“合并”,而是“不切”;切分发生在 false 处。
常见错误是写成单参数 lambda:[&](int x) { return x % 2 == 0; } —— 编译直接失败,因为 chunk_by 会传两个参数进去。
立即学习“C++免费学习笔记(深入)”;
- 正确写法(按奇偶连续性分块):
[](int a, int b) { return (a % 2) == (b % 2); } - 正确写法(按字符串首字母是否相同):
[](const std::string& a, const std::string& b) { return !a.empty() && !b.empty() && a[0] == b[0]; } - ⚠️ 注意:空序列或单元素序列不会触发谓词调用,第一个 chunk 总是至少含一个元素
chunk_by 返回的是什么?怎么安全遍历?
chunk_by 返回一个 view,其 value_type 是 std::ranges::subrange<It>(即一对迭代器),不是 std::vector 或容器。你不能直接对 chunk 做 .size() 或 std::distance,除非你先转成范围操作(如 std::ranges::distance)。
更关键的是:chunk 的 lifetime 依赖于原 range —— 如果原 range 是临时对象(比如函数返回的 vector),而你保存了 chunk 的 subrange,可能引发 dangling iterator。
- 安全遍历方式(推荐):
for (auto chunk : vec | std::views::chunk_by([](int a, int b) { return a <= b; })) { for (int x : chunk) { /* 处理每个元素 */ } } - 获取 chunk 长度:
std::ranges::distance(chunk),不是chunk.end() - chunk.begin()(因为可能不是 random_access_iterator) - 避免保存 subrange:不要写
auto first_chunk = ... | std::views::chunk_by(...).begin();,除非你确保原 range 生命周期足够长
性能与兼容性要注意什么?
chunk_by 是 lazy view,不复制数据,但每次访问 chunk 都需从头推进迭代器(因为它是 input_range 级别,不支持随机跳转)。这意味着反复遍历同一 chunk 代价高——它不是 cache-friendly。
- C++23 起才可用,GCC 13+ / Clang 15+ / MSVC 19.35+ 支持;旧版本编译不过,别指望用
__gnu_cxx::slist或第三方 backport 替代 - 谓词被调用次数 ≈ 原 range 长度 − 1,所以避免在谓词里做重操作(如文件 IO、内存分配)
- 如果原 range 是
std::vector且你频繁查 chunk 长度/随机访问,不如手动预处理成索引 vector,再用std::span切分,反而更快
真正要用好 chunk_by,得接受它是个“流式切片器”,不是“分组构造器”。它的设计意图很明确:轻量、惰性、面向相邻关系——偏离这个,就容易绕进坑里。


















