std::ranges::views::filter 不能直接传捕获 lambda,因其谓词需可默认构造、可复制且满足 std::regular_invocable;捕获 lambda 不可默认构造,导致编译失败。

std::ranges::views::filter 为什么不能直接传 lambda 捕获变量?
因为 std::ranges::views::filter 要求谓词(predicate)必须是可复制、可默认构造、且满足 std::regular_invocable 的类型。捕获 lambda(比如 [x](int n) { return n % x == 0; })不可默认构造,编译会报错:error: use of deleted function 'constexpr auto operator()(...) const' 或类似提示。
实操建议:
- 用无捕获 lambda:如
[](int n) { return n % 2 != 0; }—— 安全可用 - 若需动态参数(如过滤模
k的数),改用std::views::filter配合std::bind_front或封装为函数对象 - 避免在 filter 内部做耗时计算;谓词应轻量,否则拖慢整个视图遍历
过滤奇数的最简写法(C++20 起)
直接用无捕获 lambda 判断奇偶即可,注意返回 true 表示“保留”,不是“跳过”:
#include <ranges>
#include <vector>
#include <iostream>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5, 6};
auto odd_view = v | std::views::filter([](int n) { return n % 2 != 0; });
for (int x : odd_view) {
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>
<ul>
<li>必须用 <code>|</code> 管道操作符组合视图,不能写成 <code>std::views::filter(v, ...)</code>(后者不存在)</li>
<li>
<code>n % 2 != 0</code> 比 <code>n & 1</code> 更安全:对负数也符合数学奇偶定义(<code>-3 % 2</code> 在 C++ 中为 <code>-1</code>,所以 <code>!= 0</code> 才正确)</li>
<li>视图不拷贝数据,<code>odd_view</code> 是惰性求值的,直到你开始迭代才计算</li>
</ul>
<h3>和传统 std::copy_if + std::back_inserter 对比有什么区别?</h3>
<p><code>std::views::filter</code> 不分配内存、不修改原容器、不立即执行,而 <code>std::copy_if</code> 是 eager(急切)算法,会立刻把结果写入目标容器。</p>
<p>实操建议:</p>
<ul>
<li>只读遍历或链式处理(比如再接 <code>std::views::transform</code>)—— 优先用 <code>views::filter</code>
</li>
<li>需要物化结果(如存进新 <code>std::vector</code>)—— 加上 <code>std::ranges::to<:vector></:vector></code>:<code>v | std::views::filter(...) | std::ranges::to<:vector></:vector></code>
</li>
<li>调试时别忘了:视图本身没有 <code>.size()</code>(除非是 sized_range),打印前先转 <code>std::vector</code> 或用 <code>std::ranges::distance</code>
</li>
</ul>
<h3>常见编译错误及修复</h3>
<p>典型报错:<code>no match for 'operator|'</code> 或 <code>ranges::filter_view requires a viewable_range</code>。</p>
<p>原因和修复:</p>
<ul>
<li>忘记包含头文件:<code>#include <ranges></ranges></code> —— 必须有,<code><algorithm></algorithm></code> 不够</li>
<li>对非 viewable 类型使用(如原生数组未转 <code>std::span</code> 或 <code>std::ranges::subrange</code>):<code>int arr[] = {1,2,3}; auto v = arr | std::views::filter(...);</code> ❌;应写成 <code>std::span{arr} | std::views::filter(...)</code> ✅</li>
<li>VS2019 默认不启用 C++20 范围库:需确认项目设置中启用了 <code>/std:c++20</code> 且已安装支持 ranges 的 SDK</li>
</ul>
真正容易被忽略的是:filter 视图的迭代器不是随机访问的,哪怕底层容器是 <code>std::vector</code>,filter 后的视图迭代器只保证前向(forward_iterator),<code>it + 5</code> 会编译失败。需要随机访问时,必须先物化。</int></iostream></vector></ranges>C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










