std::ranges::views::chunk_by是按相邻元素二元谓词结果翻转动态切分序列的视图,而std::ranges::views::chunk是按固定大小位置驱动切分;前者返回subrange序列,后者返回等长块,二者语义完全不兼容。

chunk_by 是什么,它和 chunk 有什么区别
std::ranges::views::chunk_by 不是按固定长度切分,而是根据相邻元素是否满足某个二元谓词来动态划分逻辑组。它和 std::ranges::views::chunk 完全不同:chunk 按 size 切(比如每 3 个一组),而 chunk_by 看“断点”——当 pred(*it, *(it+1)) 为 false 时,就在此处切一刀。
典型场景:把连续相同值的子序列归为一组(类似 Python 的 itertools.groupby),或按单调性变化分段(如升序段、降序段)。
- 必须传入一个二元谓词(
std::binary_predicate),不能省略 - 输入范围必须是 forward_range,且至少支持
++it和*it - 返回的是 view,不拷贝数据;每个 chunk 是一个
subrange,需用std::ranges::begin/end或范围 for 访问
怎么写谓词才能正确分组连续相等元素
最常见需求是“把 [1,1,2,2,2,3] 分成 {1,1}, {2,2,2}, {3}”,此时谓词应返回 true 表示“属于同一组”,即:当前元素和下一个元素“相容”,不应在此处分割。
所以判断连续相等,要写成 [=](const auto& a, const auto& b) { return a == b; },而不是 a != b。写反会导致每组只含 1 个元素。
std::vector<int> v = {1,1,2,2,2,3};
auto groups = v | std::ranges::views::chunk_by([](int x, int y) { return x == y; });
for (const auto& chunk : groups) {
std::cout
<p>输出:</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/gongju/2823" title="C++14"><img
src="https://img.php.cn/upload/manual/001/431/639/6ac8b33c327c4749.png" alt="C++14" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/gongju/2823" title="C++14" class="overflowclass">C++14</a>
<p class="overflowclass">C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。</p>
</div>
<a rel="nofollow" href="/xiazai/gongju/2823" title="C++14" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>
<p>group: 1 1 <br>group: 2 2 2 <br>group: 3</p>
<h3>chunk_by 在 vector vs list 上的行为差异</h3>
<p><code>chunk_by</code> 内部需要对迭代器做自增和解引用操作,因此要求底层容器支持 forward iteration。这在 <code>std::vector</code> 和 <code>std::list</code> 上都满足,但性能表现不同:</p>
<ul>
<li>
<code>std::vector</code>:随机访问快,chunk_by 迭代高效;各 chunk 的 <code>begin()/end()</code> 是普通指针或随机访问迭代器</li>
<li>
<code>std::list</code>:每次 <code>++it</code> 是 O(1),但遍历仍比 vector 慢;各 chunk 的迭代器是双向的,不能直接算距离</li>
<li>⚠️ <code>std::forward_list</code> 不行:它不支持 <code>std::ranges::size</code>,且 <code>chunk_by</code> 内部可能隐式依赖多遍遍历能力(标准未强制要求 single-pass),实践中多数实现会拒绝编译</li>
</ul>
<h3>常见编译错误和坑</h3>
<p>最常遇到的错误是谓词签名不匹配或范围不可见:</p>
<ul>
<li>
<code>error: no matching function for call to 'chunk_by'</code>:多半因为没引入 <code><ranges></ranges></code>,或用了 C++20 之前的编译模式(需 <code>-std=c++20</code>)</li>
<li>
<code>error: use of deleted function 'operator='</code>:试图把 <code>chunk_by</code> view 赋给 <code>std::vector<auto></auto></code> —— view 不可直接构造容器,要用 <code>std::ranges::to<:vector></:vector></code> 或手动拷贝</li>
<li>谓词捕获外部变量但未声明 <code>mutable</code>:如果谓词里修改了捕获变量(比如计数器),lambda 必须加 <code>mutable</code>,否则编译失败</li>
<li>空 range 输入:<code>chunk_by</code> 对空 range 返回空 view,安全,但别假设至少有一个 chunk</li>
</ul>
<p>真正麻烦的是谓词逻辑边界——比如按大小分组时写成 <code>x ,那 [1,3,2] 会被切成 [1,3], [2],但 [1,2,3] 就变成一整组。这种语义必须和业务目标严格对齐,没法靠试错解决。</code></p></int>C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










