std::ranges::views::values仅适用于元素为pair-like类型(如std::pair、std::tuple或支持结构化绑定的类型)的范围,用于提取second成员视图;对vector等不适用,且视图不拷贝数据、不提供随机访问、依赖容器生命周期。

std::ranges::views::values只能用于关联容器,不能用在vector或array上
直接对 std::vector<int></int> 或 std::array<:pair char>, 3></:pair> 调用 std::ranges::views::values 会编译失败,错误信息通常是:no matching function for call to 'values' 或更具体的 static_assert failed: "views::values requires a range of pair-like types"。它只接受能解构为 first/second 成员(或支持结构化绑定)的类型,典型如 std::map、std::unordered_map、std::set<:pair>></:pair> 等。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 确认源容器元素类型是否满足
std::is_pair_like_v<t></t>(C++23 中定义),常见合法类型:std::pair<k></k>、std::tuple<k></k>、自定义含first和second的结构体(需提供get/get或支持结构化绑定) - 若你手头是
std::vector<:pair std::string>></:pair>,可以用;但std::vector<int></int>不行 —— 此时应改用std::ranges::views::all或直接范围 for - 注意:
std::map本身是std::pair<const k v></const>序列,所以views::values提取的是V类型子视图,且保留 const 性(即得到std::ranges::ref_view<const v></const>)
std::ranges::views::values返回的是视图,不是拷贝,修改原容器会影响遍历结果
它不复制数据,只是生成一个轻量级的“投影”视图。对底层容器做插入、擦除、修改元素值等操作后,再次遍历该视图会反映最新状态 —— 这是预期行为,但容易误以为是“快照”。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 避免在遍历
views::values的同时修改容器大小(如erase或insert),这可能导致迭代器失效,引发未定义行为(和普通迭代器一样) - 可以安全地修改 value 成员(比如
std::map<int std::string></int>中的string内容),因为views::values返回的是引用(V&或const V&) - 示例:
std::map<int, std::string> m = {{1, "a"}, {2, "b"}};<br>auto vals = m | std::ranges::views::values;<br>for (auto& s : vals) s += "!"; // 合法,m[1] 变成 "a!",m[2] 变成 "b!"
和传统 for 循环或 transform 相比,views::values 的性能开销几乎为零
它不分配内存,不复制元素,底层只是调整迭代器的 operator* 行为,让其返回 iter->second。编译器通常能完全内联,汇编级别和手写循环无差别。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 不必担心“视图抽象带来性能损失”,放心在 hot path 使用
- 但它不提供随机访问(除非底层容器支持且视图适配器保留了该特性)——
views::values对std::map返回的是前向视图(forward_range),不支持operator[]或random_access_iterator - 若你需要索引访问(如取第 3 个 value),得先转成 vector:
std::vector<v>(vals.begin(), vals.end())</v>,但这会触发拷贝 —— 注意权衡
使用 views::values 时容易忽略 const 限定导致编译失败
对 const 容器调用 views::values,得到的是 const V& 视图;若尝试用非 const 引用接收,会报错:cannot bind non-const lvalue reference to an rvalue 或类似。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 统一用
auto&或const auto&捕获,让类型推导自动适配:const std::map<int, std::string> cm = {{1,"x"}};<br>auto vals = cm | std::ranges::views::values;<br>for (const auto& s : vals) { /* ok */ } // 必须加 const - 如果后续要修改 value,确保源容器本身非常量,且 value 类型可写(例如
std::map<int std::string></int>可以,但const std::map<int std::string></int>不行) - 不要写
auto& v = ... | views::values然后在 const 上下文中用 —— 编译器不会帮你“降 const”
视图的生命期必须严格短于其引用的容器,这是所有 range adaptor 的通用约束,views::values 尤其明显:一旦容器析构,继续使用该视图就是野指针。别把它存成成员变量或跨作用域传递,除非你明确控制了生命周期。


















