chunk_by按相邻元素比较结果切分而非按值分组,仅对连续重复有效;要求输入范围生命周期长于视图,且需用std::ranges::distance获取长度、*chunk.begin()获取首值。

chunk_by 的核心行为:它不按值分组,而是按相邻元素的比较结果切分
std::ranges::views::chunk_by 不是“把相同值的元素归到一起”,而是根据一个二元谓词(默认是 std::equal_to{})判断**相邻两个元素是否属于同一段**。只要 pred(*it, *(it+1)) 为 true,它们就连在一起;一旦为 false,就在此处切开。所以它天然适合处理连续重复序列(run-length grouping),但对非连续重复无效。
常见错误是误以为它等价于 Python 的 itertools.groupby —— 实际上语义一致,但 C++ 版本要求输入范围支持前向迭代器(std::vector、std::string 没问题,std::list 也行;但纯输入范围如 std::istream_view 不可用)。
- 必须传入一个可调用对象作为谓词,哪怕只是
std::equal_to{} - 返回的是一个视图,每个元素是一个子视图(
std::ranges::subrange),不是std::vector或容器 - 原始范围不能是临时对象(比如函数返回的局部
std::vector),否则子视图会悬空
正确写法:用 std::equal_to{} 处理连续相同元素
假设你有一个 std::vector<int></int>,想把连续相同的数字各自打包成一组:
std::vector v = {1,1,2,2,2,3,1,1};<br>auto groups = v | std::views::chunk_by(std::equal_to{});<br>// groups 是一个 view,每个元素是 subrange<iter></iter>
遍历时需解引用每个子视图获取首元素或长度:
for (const auto& chunk : groups) {<br> std::cout }
输出:length=2, value=1、length=3, value=2、length=1, value=3、length=2, value=1。
- 不能直接对
chunk调用.size()(它不是容器)——得用std::ranges::distance(chunk) - 如果只关心首元素,用
*chunk.begin()安全;若要所有元素,需遍历chunk本身 - 谓词参数顺序是
(a, b),即当前元素和下一个元素;所以std::greater{}会按递减连续段切分
容易踩的坑:lambda 捕获与临时范围生命周期
下面这段代码有严重隐患:
auto make_groups() {<br> std::vector v = {1,1,2,2};<br> return v | std::views::chunk_by(std::equal_to{}); // ❌ 返回悬空视图<br>}
因为 v 在函数结束时销毁,而返回的视图仍持有其迭代器。运行时行为未定义。
- 解决方案一:把数据存为
static或类成员,确保生命周期长于视图 - 解决方案二:立即消费视图(如转成
std::vector<:vector>></:vector>):std::vector<:vector>> result; for (const auto& c : groups) result.emplace_back(c.begin(), c.end());</:vector> - 若用 lambda 作谓词且捕获了局部变量,同样会导致悬空 —— 捕获必须是值拷贝或静态引用
替代方案:什么时候不该用 chunk_by?
如果你需要的是「所有值相同的元素不管位置全归一组」(即传统意义上的 group-by),chunk_by 完全不合适。它只看相邻关系。
例如 {1,2,1,2} 经 chunk_by(std::equal_to{}) 会切成四段,每段长度为 1 —— 因为没有相邻相等元素。
- 真要全局分组,得先排序再用
chunk_by,或者用std::unordered_map手动聚合 - 如果输入是
std::string_view或字面量字符串,注意std::string_view的 lifetime 必须覆盖整个视图使用期 - 在 MSVC 2022 17.5+ 和 GCC 13+ 上支持良好;Clang 15+ 需开启
-std=c++20且启用__cpp_lib_ranges
真正用起来,关键就两点:确认你要的是连续段,且确保底层数据活得比视图久。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











