Range-V3获取基础迭代器问题:find_if结果无法转为std::map迭代器
首先咱们来拆解你遇到的核心问题:
你通过reverse+values视图后的范围调用ranges::find_if,返回的迭代器是经过两层视图适配后的包装迭代器——它指向的是std::map的value部分(也就是std::wstring),而且因为reverse_view的嵌套,直接调用.base()没办法一步拿到原map的迭代器,这就是编译失败的根源。
为什么编译报错?
看你的错误信息:当前的迭代器ranges::v3::basic_iterator是values_view的迭代器,它的.base()返回的是reverse_view的迭代器。这个reverse_view迭代器并没有重载operator->直接让你访问first,更关键的是:values_view已经把迭代器的访问范围限制到了map的value字段,从这个迭代器本身已经丢失了原key-value对的关联信息,所以你没法直接从它拿到原map的pair<const int, std::wstring>。
正确的解决方案
方案1:保留key-value对进行查找(推荐)
既然你之后需要原map的迭代器,一开始就不要用values_view,直接在reverse后的map范围上查找,判断value即可:
std::map<int, std::wstring> ss = { {1,L"1"}, {2,L"2"}, {3,L"3"} }; // 只做reverse视图,保留完整的key-value对 auto rng = ss | ranges::view::reverse; // 查找时判断pair的second字段 auto it = ranges::find_if(rng, [](auto&& kv_pair) { return kv_pair.second == L"2"; }); if (it != rng.end()) { // reverse_view的迭代器.base()返回原map的反向迭代器 // 再调用一次.base()就能拿到原map的正向迭代器 auto original_map_it = it.base().base(); assert(original_map_it->first == 2); // 现在编译正常 }
方案2:如果一定要用values_view(不推荐)
如果你因为某些场景必须使用values_view,那你需要放弃从find_if返回的迭代器直接拿原map迭代器,而是换一种方式(比如通过value反向查找原map,但这会损失性能,因为map查找value是O(n)的),所以更推荐方案1。
关于ranges::find_if返回的迭代器类型
ranges::find_if返回的迭代器类型是对应输入范围的迭代器类型——在你的代码里,输入范围是reverse_view<values_view<map>>,所以返回的是values_view的迭代器,它的底层是嵌套了reverse_view迭代器的ranges::v3::basic_iterator。这种适配迭代器的.base()方法只能返回上一层视图的迭代器,所以你需要逐层解开:
it.base()→reverse_view的迭代器it.base().base()→ 原map的反向迭代器it.base().base().base()→ 原map的正向迭代器(但前提是你没有用values_view,因为values_view已经把迭代器指向了value,丢失了pair信息)
内容的提问来源于stack exchange,提问作者Alexey Subbota

