C++如何使用 std::ranges::views::keys 遍历有序字典的所有键

std::ranges::views::keys 仅适用于满足 tuple-like 要求的关联容器(如 std::map),不保证兼容 std::unordered_map;必须用管道操作符 | 使用,返回 const K& 视图,零成本抽象但需注意生命周期和只读约束。

c++如何使用 std::ranges::views::keys 遍历有序字典的所有键

std::ranges::views::keys 只能用于关联容器,不能用于 std::unordered_map

它要求底层视图的元素类型是 std::pair<const k v></const> 且支持 std::get(e) —— 这在 std::mapstd::set(注意:set 的 pair 是 std::pair<const k void></const>)等有序容器中成立,但 std::unordered_map 的迭代器解引用结果虽也是 std::pair<const k v></const>,其内部实现却可能不满足 std::ranges::viewable_range + std::tuple_size_v 约束(尤其在较旧标准库如 libstdc++ 12 前),导致编译失败或未定义行为。

常见错误现象:

  • error: no matching function for call to 'keys'(GCC 12.2 或更低)
  • static_assert failed: "views::keys requires a range of tuple-like types"

实操建议:

  • std::mapstd::multimap 替代 std::unordered_map,若仅需键遍历且顺序无关,改用传统循环:for (const auto& [k, v] : umap) { /* use k */ }
  • C++23 起部分标准库(如 MSVC 19.35+、libstdc++ 13+)已放宽限制,但仍建议优先验证 std::ranges::views::keys(umap) 是否可编译

必须配合 range adaptor pipe operator 使用,不能直接构造

std::ranges::views::keys 是一个 range adaptor object,不是函数模板也不是视图类型,不能像 std::views::filter 那样传参调用;它只能通过管道操作符 | 应用于一个适配的 range。

立即学习“C++免费学习笔记(深入)”;

错误写法:

auto keys_view = std::ranges::views::keys(my_map); // ❌ 编译失败

正确写法:

auto keys_view = my_map | std::ranges::views::keys; // ✅

使用场景:

  • 链式组合时必须保持左结合:my_map | std::views::keys | std::views::take(3)
  • 若想提前获取键视图并复用,需用 auto 推导(不可用 std::ranges::keys_view,该类型未公开)
  • 不能对临时 map 写 std::map<int char>{} | std::views::keys</int>,因为临时对象生命周期不足以支撑视图迭代

遍历时 key 类型是 const 引用,修改 key 会触发未定义行为

std::ranges::views::keys 返回的每个元素是底层 std::pair 中 first 成员的 const& —— 即 const K&。试图通过它修改 key(比如 *it = new_key)既不可行,也不合法。

常见错误现象:

  • error: assignment of read-only location
  • 即使绕过编译(如 const_cast),也会破坏 map 内部红黑树结构,后续查找/插入崩溃

实操建议:

  • 只读遍历:直接用 for (const auto& k : map | std::views::keys) { ... }
  • 需要替换 key?必须先 erase 原键值对,再 insert 新的 {new_key, value}
  • 若需同时访问 key 和 value,别拆成两步,直接用结构化绑定:for (const auto& [k, v] : map) { ... }

性能无额外开销,但底层仍依赖 map 迭代器遍历

std::views::keys 是零成本抽象:它不拷贝键,不分配内存,只是重定向迭代器的 operator* 返回 it->first。时间复杂度与原容器迭代完全一致(O(n),每次 ++ 是摊还常数)。

但要注意:

  • 它不改变底层容器的遍历顺序 —— std::map 仍是升序,std::multimap 按 key 排序后按插入顺序稳定
  • 如果 map 很大且只取前几个键,配合 std::views::take 可提前终止,但 std::views::keys 本身不提供随机访问,无法 keys_view[5]
  • 调试时观察 keys_view 类型会看到类似 std::ranges::ref_view<:map>></:map>,说明它只是包装而非复制

真正容易被忽略的是:你得确保 map 本身没被移动或析构 —— 视图不拥有数据,悬空引用比裸指针更隐蔽。

文章来自机圈观察员网,发布者:,转载请注明出处:https://www.jqgcy.com/shoujipingce/123969.html

如何利用CSS Grid实现全屏单页翻页布局?
上一篇 2026-07-01 15:26
HTML文档结构之容器嵌套的逻辑合法性
下一篇 2026-07-01 15:52

相关推荐