std::ranges::views::keys 仅适用于支持结构化绑定的标准关联容器(如 std::map),要求 C++20 支持、value_type 为可解构的 std::pair,返回只读 view,不可随机访问,遍历时禁止修改原容器,且 GCC 12+/MSVC 19.35+/Clang 15+ 才完整支持。

std::ranges::views::keys 要求容器支持结构化绑定
直接对 std::map 或 std::unordered_map 使用 std::ranges::views::keys 是合法的,但前提是编译器和标准库支持 C++20 的范围适配器,并且底层容器的 value_type 必须能被结构化绑定 —— 而 std::pair<const k v></const> 满足这一条件。不过,常见错误是误传非关联容器(比如 std::vector<:pair int>></:pair>),它虽有 pair,但 views::keys 会尝试解构为 (key, value),若 pair 不是 const key 就可能触发 SFINAE 失败或编译报错。
-
std::map、std::unordered_map、std::multimap等标准关联容器可直接用 -
std::vector<:pair std::string>></:pair>这类容器不能直接用views::keys,因为其 key 不是 const,解构失败 - 使用前确保开启 C++20:编译选项需含
-std=c++20(GCC/Clang)或/std:c++20(MSVC)
必须配合 range-based for 或其他视图组合使用
std::ranges::views::keys 返回的是一个 view,不是容器,不能直接赋值给 std::vector 或取 .size()(除非调用 std::ranges::size)。常见误区是写成 auto keys = my_map | std::ranges::views::keys; 然后试图用 keys[0] 访问 —— 这会编译失败,因为 view 默认不支持随机访问。
- 正确遍历:
for (const auto& k : my_map | std::ranges::views::keys) { ... } - 转成 vector:
std::vector keys_vec(my_map | std::ranges::views::keys | std::ranges::to<:vector>);</:vector>(需#include <ranges>和<vector>) - 链式过滤:
my_map | std::ranges::views::keys | std::ranges::views::filter([](int k) { return k > 0; })
注意 const 性与迭代器失效行为
通过 views::keys 得到的键视图是只读的,且底层仍引用原 map。如果在遍历 keys 视图时修改原 map(如 insert/erase),可能导致未定义行为 —— 这不是 views::keys 的 bug,而是所有 range view 的共性:view 不拥有数据,也不保证迭代期间容器稳定。
- 不要在
for (auto k : map | views::keys)循环体内调用map.erase(k) - 若需边遍历边删除,先收集要删的键(如存入
std::vector),再统一 erase - map 迭代器在插入新元素时可能失效(取决于是否引起 rehash 或 tree rebalance),keys view 的迭代器也会随之失效
MSVC 19.35+ 和 GCC 12+ 才提供完整支持
早期标准库实现(如 libstdc++ 11、MSVC 19.33 及更早)要么缺失 views::keys,要么对其 ADL 查找不完善,导致 “no match for call to ‘keys’” 类错误。即使代码语法正确,链接或模板实例化阶段也可能失败。
立即学习“C++免费学习笔记(深入)”;
- GCC 用户检查版本:
g++ --version≥ 12.1;并确认__cpp_lib_ranges宏已定义(可通过#ifdef __cpp_lib_ranges判断) - Clang 需搭配较新 libc++(≥ 15.0)
- MSVC 用户至少需 Visual Studio 2022 v17.5(对应 MSVC 19.35)
- 若环境不满足,退而求其次:用
std::transform(map.begin(), map.end(), back_inserter(vec), [](const auto& p) { return p.first; });
views::keys 会悄悄拒绝。


















