std::ranges::views::keys 是泛化适配器,要求元素含 first 成员,兼容 map 等键值容器,返回只读视图,需 C++20 支持,不可随机访问或修改键,不拥有数据需注意生命周期。

std::ranges::views::keys 要求容器有 value_type::first 成员
它不是专为 std::map 设计的“魔法函数”,而是泛化适配器:只要容器元素是类似 std::pair 的结构(即含 first 成员),就能提取键。所以它天然兼容 std::map、std::unordered_map,也兼容 std::vector<std::pair<int, std::string>> 这类自定义键值序列。
但注意:std::map::value_type 是 std::pair<const Key, T>,first 是 const 引用——这意味着你不能通过 views::keys 返回的视图去修改原始键(这符合语义,键本就不该被改)。
必须开启 C++20 且链接标准库范围支持
很多新手卡在这步:编译通过但运行时报错或行为异常。原因常见于:
- 没加
-std=c++20(Clang/GCC)或/std:c++20(MSVC) - 使用了旧版 libc++ 或 libstdc++(GCC 10/Clang 12 之前不完整支持
views::keys) - 忘了
#include <ranges>和#include <map>
最小可跑示例:
立即学习“C++免费学习笔记(深入)”;
#include <ranges>
#include <map>
#include <iostream>
int main() {
std::map<int, std::string> m = {{1,"a"}, {2,"b"}, {3,"c"}};
for (auto k : m | std::views::keys) {
std::cout << k << " ";
}
// 输出:1 2 3
}
不能直接对 keys 视图调用 find 或 operator[]
std::views::keys(m) 返回的是一个只读的 std::ranges::view,不是容器,也不提供查找接口。它只是把原 map 的键“投影”出来,底层仍依赖原容器迭代。
常见误用:
-
m | std::views::keys | std::ranges::find(42)—— 错!std::ranges::find可以用,但效率是 O(n),不如直接查原 map 的find()(O(log n)) -
(m | std::views::keys)[2]—— 错!keys 视图不保证随机访问(std::map的迭代器是双向而非随机),会编译失败 - 试图用
std::views::keys(m).begin()->second—— 错!keys 视图的元素是key_type(如int),没有second
与传统 for-loop 和 std::transform 的性能差异极小,但语义更清晰
它不分配内存、不拷贝键,只是包装迭代器,和手写 for (const auto& p : m) { use(p.first); } 几乎等价。但它让意图一目了然:你明确在“处理键序列”。
适合场景:
- 配合管道操作,比如
m | std::views::keys | std::views::filter(&is_even) | std::views::take(5) - 传给接受
std::ranges::input_range的算法(如std::ranges::all_of) - 避免手写
p.first,减少拼写错误
真正要注意的其实是生命周期:视图不拥有数据,m 必须活过视图使用期,否则迭代会悬垂。


















