c++oding="utf-8" ?>
std::ranges::contains是c++23新增的o(n)线性查找算法,适用于vector、array等序列容器,不适用于unordered_set等哈希容器;要求范围支持begin/end、元素可比较,参数顺序为(range, value),不支持自定义谓词。

std::ranges::contains 是 C++23 新增的算法,但不是所有容器都能直接用
它只对支持 begin()/end() 且元素可比较的范围有效,底层调用 std::ranges::find + 比较。原生数组、std::vector、std::list、std::string 都可以;但 std::unordered_set 这类哈希容器不推荐——它本应是 O(1) 查找,而 std::ranges::contains 强制走线性遍历,性能掉回 O(n)。
常见误用现象:std::ranges::contains(my_set, x) 看似简洁,实则绕过哈希查找逻辑,编译通过但运行变慢。
- 适用场景:快速判断
std::vector、std::array、C 风格数组是否含某值,尤其配合视图(如std::views::filter后接contains) - 不适用场景:已知是哈希或有序结构(如
std::set),应优先用.contains()成员函数(C++20 起)或std::binary_search - 注意:要求
operator==对元素类型可用;若自定义类型未定义该运算符,编译失败,错误信息类似no match for 'operator=='
std::ranges::contains 的参数顺序和返回值很反直觉
签名是 std::ranges::contains(range, value),不是 contains(value, range)。这个顺序和 std::find 一致,但和很多语言(如 Python 的 in)相反,容易写反导致编译错误或逻辑错位。
典型错误现象:std::ranges::contains(x, vec) 编译不过,报错指向 range 类型推导失败,因为 x 不是范围;更隐蔽的是把 value 写成指针或临时对象,引发比较行为异常。
- 必须确保第一个参数是范围(有
begin/end),第二个是待查值 - 值类型需能隐式转换为范围中元素类型,否则触发 SFINAE 失败,错误信息冗长(如
no type named 'iterator'实际是参数倒置) - 返回
bool,无额外状态;不提供位置信息——要索引请改用std::ranges::find
和传统写法比,它省了头文件和命名空间,但没省迭代器
你不用写 #include <algorithm></algorithm> 和 std::find(vec.begin(), vec.end(), x) != vec.end(),但依然要包含 <ranges></ranges>(C++23),且依赖 ADL 查找——如果范围类型在非标准命名空间里,可能找不到 contains。
示例对比:
std::vector<int> v = {1, 2, 3, 4};
// 传统
bool found = std::find(v.begin(), v.end(), 3) != v.end();
// C++23
bool found = std::ranges::contains(v, 3); // 更短,但需 <ranges></ranges></int>
- 不需要手动传
begin/end,避免迭代器失效风险(比如传错容器的迭代器) - 不支持自定义比较谓词(如忽略大小写查找字符串),这点不如
std::find_if灵活 - 对 C 风格数组有效:
int arr[] = {1,2,3}; std::ranges::contains(arr, 2)可用,但要注意数组退化问题
MSVC / GCC / Clang 支持情况差异大,别在 C++20 项目里硬上
Clang 15+(启用 -std=c++2b)和 GCC 13+ 默认支持;MSVC 19.34+(VS 2022 17.4+)才开始实验性支持,且需 /std:c++23。低版本编译器会静默忽略或报 namespace 'std::ranges' has no member 'contains'。
容易踩的坑:CI 环境用旧版 GCC,本地开发用新 Clang,代码在本地跑通,上线构建失败。
- 检查编译器版本再决定是否启用:GCC
__GNUC__ >= 13,Clang__clang_major__ >= 15 - 跨平台项目建议暂时封装一层 fallback:
#ifdef __cpp_lib_ranges_contains判断特性宏 - 即使编译通过,某些 STL 实现(如 libstdc++ 早期 C++23 快照)可能把
contains当作未完成特性,行为不稳定
std::ranges::contains 确实让简单成员检查变短了,但它不是银弹——类型约束、性能陷阱、编译器碎片化,每个都可能在深夜调试时跳出来。C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











