C++23:如何从vector中删除find_if返回的反转滑动子范围?
问题解决:从vector中删除视图迭代器对应的子范围
你遇到的核心问题是:views::reverse和views::slide生成的是视图,ranges::find_if返回的是视图迭代器,无法直接传给vector::erase(后者要求原容器的正向迭代器)。但完全可以通过视图迭代器的base()方法映射回原vector的迭代器,无需重复查找,直接执行erase操作。
转换逻辑
views::reverse的迭代器是反向迭代器,调用base()可得到对应的正向迭代器,但要注意:反向迭代器rev_it指向的元素等价于*(rev_it.base() - 1)。slide视图的迭代器解引用后得到的子范围是反向视图的连续区间,将这个子范围的起始、结束反向迭代器转换为正向迭代器后,就能得到原vector中需要删除的区间。
修改后的核心函数代码
#include <vector> #include <ranges> #include <iostream> #include <algorithm> struct Data { int value; bool is_successive; }; template <typename R> std::vector<typename R::value_type> to_vector(R&& r) { return std::vector<typename R::value_type>(std::ranges::begin(r), std::ranges::end(r)); } std::vector<Data> take_last_successive_data(std::vector<Data> &target) { const auto &data_is_successive = [](const auto &data) { return data.is_successive; }; auto windows = target | std::views::reverse | std::views::slide(2); auto result = std::ranges::find_if( windows, [&](const auto &window) { return std::ranges::all_of(window | std::views::take(window.size() - 1), data_is_successive); } ); if (result == windows.end()) { std::cout << "not found\n"; return {}; } else { auto window = *result; auto rev_begin = window.begin(); auto rev_end = window.end(); // 将反向迭代器转换为原vector的正向迭代器,得到删除区间 auto first = rev_end.base() - 1; auto last = rev_begin.base(); // 执行删除操作 target.erase(first, last); auto ret = to_vector(window | std::views::reverse); for (const auto &data : ret) { std::cout << data.value << ", "; } std::cout << '\n'; return ret; } }
说明
- 先获取找到的窗口
window,再提取窗口的起始和结束反向迭代器。 rev_end.base() - 1对应原vector中待删除区间的起始位置,rev_begin.base()对应区间的结束位置(erase采用左闭右开区间)。- 这种方式直接复用了
find_if的查找结果,避免了重复遍历带来的性能损耗,且在执行erase前,转换得到的正向迭代器都是有效的(原vector未被修改)。
内容的提问来源于stack exchange,提问作者Sprite
相关产品推荐
相关产品推荐

