std::views::chunk_by按相邻元素谓词结果翻转分块,非固定长度分组;它不接受整数参数,须传二元无状态谓词,且要求forward_range、参数类型匹配、无副作用。

std::views::chunk_by 不是用来“每 N 个分一组”的,它只响应相邻元素间谓词结果的翻转——不是按长度,也不是按值相等性全局归类,而是看 (a,b) 和 (b,c) 这两对传给谓词时,返回值是否由 true 变 false(或反之)。
为什么 std::views::chunk_by(3) 编译不过
因为它的签名根本不接受整数参数。你写的 chunk_by(3) 是在试图用 int 构造一个可调用对象,而标准要求它必须接收一个二元可调用对象(Callable<t></t>)。编译器报错典型是:
error: no matching function for call to 'chunk_by(int)'
- 正确写法只能是:
v | std::views::chunk_by([](auto& a, auto& b) { return /* bool expr */; }) - 想实现“每 3 个一组”,该用
std::views::chunk(3),不是chunk_by - 若硬要用
chunk_by模拟固定长度,得靠索引状态 —— 但这是禁止的:谓词不能捕获可变变量(如[i=0](auto&, auto&) mutable { return ++i % 3 != 0; }),否则视图不可复制,后续管道操作(如接transform)直接失败
std::equal_to{} 并不等于“把相同值全归到一块”
它只比较相邻对:pred(a,b) 为 true 表示 a 和 b 属于同一块;一旦为 false,就在 b 前切一刀。输入 {1,2,1,1} 会得到 [1], [2], [1,1],不是 [1,1], [2], [1]。
- 首元素永远自成一块起点,不参与首次谓词调用
- 第 2 个元素和第 1 个比,
equal_to{}(2,1)→false→ 切,[1]结束 - 第 3 个和第 2 个比,
equal_to{}(1,2)→false→ 再切,[2]结束 - 第 4 个和第 3 个比,
equal_to{}(1,1)→true→ 不切,[1,1]形成 - 所以它本质是“连续等值段”,不是“所有等值元素聚合”
谓词必须无状态、二元、且类型匹配
常见崩溃/编译失败原因不是逻辑错,而是谓词违反约束:
立即学习“C++免费学习笔记(深入)”;
- 参数类型必须能同时接受
const T&和T&—— 若原范围是const std::vector<int>,而谓词写成(int& a, int& b),就会编译失败 - 不能捕获局部非 const 变量:
[counter](auto&, auto&) mutable { ++counter; }导致chunk_by_view不可复制,接| std::views::filter等会触发use of deleted function - 推荐安全写法:
[=](const auto& a, const auto& b) { return a.category == b.category; }(仅读捕获,且参数为 const 引用) - 谓词也不应有副作用(如修改全局状态、打印日志),因视图可能被多次遍历或惰性求值时机不确定
输入必须是 forward_range,std::list 直接不支持
chunk_by 内部需要回退迭代器做相邻比较(比如拿到 it+1 后,有时要再看 it),这要求迭代器支持多次解引用和可保存 —— std::list::iterator 虽是双向迭代器,但 std::list 不满足 forward_range 的完整语义(部分标准库实现中,std::list 仅满足 bidirectional_range,但 chunk_by 显式要求 forward_range)。
- 实测:用
std::list直接构造chunk_by_view会编译失败,提示类似static_assert failed: 'The provided range does not model forward_range' - 可行替代:转成
std::vector或用std::span包装原生数组 - 注意临时容器陷阱:
std::vector{1,2,3} | std::views::chunk_by(pred)中,vector是纯右值,其生命周期只到该表达式结束,后续遍历时迭代器悬垂
真正容易被忽略的是:它不保证块之间互斥覆盖全部语义意图 —— 比如你想“按奇偶连续段分组”,但输入是 {2,4,6,1,3,5,8,10,7},末尾 7 和前一元素 10 奇偶不同,它就单独成块,哪怕你本意是“只要奇数就合并”。这种边界行为不是 bug,而是设计使然:它只看相邻,不看上下文。


















