std::ranges::copy_if需包含和,接受范围、输出迭代器和谓词,返回copy_if_result;输入须为input_range,输出须为output_iterator;谓词参数应适配元素类型(如const auto&);避免未reserve的back_inserter导致重分配;相比传统copy_if,支持范围语义且更安全。

std::ranges::copy_if 的基本用法和必要头文件
必须包含 <algorithm></algorithm> 和 <ranges></ranges>(C++20 起),否则编译报错 error: ‘copy_if’ is not a member of ‘std::ranges’。只引 <algorithm></algorithm> 不够,因为 std::ranges::copy_if 是独立于传统 std::copy_if 的重载集合。
它接受范围(range)、输出迭代器、谓词(predicate),返回一个 std::ranges::copy_if_result 结构体(含 in 和 out 成员),不是 void。
- 输入必须是满足
std::ranges::input_range的类型(如std::vector、std::array、原始数组、std::string) - 输出目标需支持
std::ranges::output_iterator,常见的是std::back_inserter或已预留空间的容器迭代器 - 谓词可为 lambda、函数指针或函数对象,参数类型由范围元素自动推导
为什么不能直接用 std::back_inserter 配合未预留空间的 vector
如果目标 std::vector 是空的,又用 std::back_inserter,虽然能工作,但频繁 push_back 可能触发多次内存重分配——尤其数据量大时性能明显下降。这不是语法错误,而是隐性开销。
- 正确做法:先用
std::ranges::count_if预估数量,调用reserve() - 或改用
std::vector::begin()+std::vector::end()(前提是已 resize 到足够大小) - 示例:
std::vector<int> out; out.reserve(std::ranges::count_if(v, pred)); std::ranges::copy_if(v, std::back_inserter(out), pred);</int>
常见编译错误:谓词参数类型不匹配
lambda 捕获或参数声明不当会导致 SFINAE 失败,典型错误信息:no matching function for call to ‘copy_if’,深层原因是谓词无法接受 range 的 value_type。
- 若 range 元素是
const int&,lambda 写成[&](int x) { ... }就可能失败(x 是值拷贝,但传入的是 const 引用) - 稳妥写法统一用
[&](const auto& x) { ... }或[&](auto x) { ... }(依赖隐式转换) - 注意:若 range 是
std::vector<:string></:string>,而谓词里写了std::string_view参数,需确保 view 能从 string 构造(C++17 起支持),否则编译不过
与传统 std::copy_if 的关键区别:范围语义 vs 迭代器对
std::ranges::copy_if 直接接收整个范围(比如 v),不再需要传 v.begin(), v.end();输出端也支持范围(如 std::ranges::subrange{out.begin(), out.end()}),但更常用 std::back_inserter 或 std::ranges::begin(out)。
- 旧式写法:
std::copy_if(v.begin(), v.end(), std::back_inserter(out), pred); - 新式写法:
std::ranges::copy_if(v, std::back_inserter(out), pred); - 真正省事的是组合操作:比如
std::ranges::copy_if(v | std::views::filter(pred), std::back_inserter(out));—— 但注意这会两次遍历(filter 视图 + copy_if),不如单次copy_if高效
真正容易被忽略的是:当输入范围是临时对象(如函数返回的 std::vector),std::ranges::copy_if 能绑定到其生命周期,而传统迭代器写法可能因 .begin() 返回悬垂迭代器出问题——这点在重构代码时尤其关键。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











