std::views::chunk_by 不是按值分组,而是在相邻元素间谓词结果翻转处切分;它只比较当前与前一个元素,不追溯历史,也不接受整数参数,且要求输入为 forward_range(如 vector),不可用于 list 或含非常量引用捕获的 lambda。

直接说结论:std::views::chunk_by 不是“按值分组”,而是“在相邻元素间谓词结果翻转的位置切一刀”;它只看 (a, b) 和 (b, c) 的谓词返回值是否不同,不关心全局相等性,也不接受整数参数。
为什么 std::views::chunk_by(std::equal_to{}) 没按预期分组?
常见错误现象:对 {1,2,1,1} 用 std::equal_to{},期望得到 [1], [2], [1,1],结果确实是这个——但逻辑上不是“把所有 1 归为一组”,而是:
- 比较
1和2→false→ 切一刀([1]结束) - 比较
2和1→false→ 再切一刀([2]结束) - 比较
1和1→true→ 不切,继续归入当前块 → 得到[1,1]
关键点在于:它不追溯历史,只看“当前 vs 前一个”。所以 [1,1] 成立,跟第一个 1 完全无关。若你真需要“所有相同值归为一组”,得先排序再用 chunk_by,或改用 std::ranges::group_by(C++26 起草案中已讨论,但尚未标准化)。
传 lambda 时捕获局部变量导致编译失败
错误示例:int counter = 0; auto v = r | std::views::chunk_by([&counter](int a, int b) { return ++counter % 2; });
立即学习“C++免费学习笔记(深入)”;
问题根源:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
-
chunk_by_view对象必须可复制(用于管道组合,如后续接| std::views::transform),而捕获非常量引用的 lambda 不可复制 - 编译器报错通常是
use of deleted function或copy constructor is implicitly deleted - 即使没报错,行为也是未定义:同一对
(a,b)多次调用可能返回不同结果
安全写法:
- 仅读捕获:
[=](int a, int b) { return a / 10 == b / 10; }(按十位分组) - 无捕获:
[](int a, int b) { return (a & 1) == (b & 1); }(奇偶性) - 用函数对象:
std::less{}、std::equal_to{}等标准对象,天然满足要求
std::list 或 std::forward_list 传进去就编译失败
错误信息典型为:static_assert failed: 'The range argument to views::chunk_by must model forward_range'
原因很实在:
-
chunk_by内部需回退一个位置做比较(即访问it和prev(it)),这要求迭代器支持多次解引用且能保存位置 -
std::list::iterator是双向迭代器,但std::list不满足forward_range吗?不,它满足——但问题出在std::list的迭代器在插入/擦除后极易失效,而chunk_by_view的实现依赖稳定迭代器状态,主流标准库(如 libstdc++、libc++)直接拒绝非随机访问或非连续容器的前向范围(实际是保守策略) - 真正稳妥可用的只有:
std::vector、std::array、原生数组、std::string、std::span
临时解决办法:先转存 std::vector,别硬刚:
std::list<int> l = {1,2,2,3};
std::vector<int> v(l.begin(), l.end());
auto chunks = v | std::views::chunk_by(std::equal_to{});
chunk_by 和 chunk 完全不是一回事,别混着用
最常被忽略的点:名字像,签名和语义毫无关系。
-
std::views::chunk(3):接受整数,按固定长度切,类型是size_t,输入必须是sized_range -
std::views::chunk_by(pred):接受二元可调用对象,只看相邻元素谓词变化,输入只需forward_range - 写成
v | std::views::chunk_by(3)→ 编译报错:no matching function for call to 'chunk_by(int)' - 误以为
chunk_by能替代split:它不找“分割符”,不剔除任何元素,切口永远在两元素之间
复杂点在于:chunk_by 的切分点不可预知,依赖运行时谓词结果;一旦原容器发生修改(比如 vector::push_back 触发重分配),所有已构造的 chunk_by_view::iterator 立即失效——比 chunk 更脆弱,这点容易被忽略。

















