使用 Ranges-V3

问题描述

我有两个向量:

struct MyData{
     double value; 
};
std::vector<int> remove_flags = {0,1,0};
std::vector<MyData> data =      {{},{},{}}; 

remove_flags 向量包含与 data 大小完全相同的标志数组,每个标志是 0 或 1,其中 1 表示应删除数据。

我想使用 remove_flags 就地从 data删除元素,即执行擦除删除习语,但根据 remove_flags 中的值进行擦除。最终结果应该是 data 删除了元素,希望 remove_flags 删除了相同的元素。

手动执行此操作很烦人,我想为此使用 Range-v3。我目前使用的是 C++17。

在查看文档后,我认为我没有找到解决方案,我能想到的最接近的事情是:

auto result = ranges::views::zip(remove_flags,data) | ranges::actions::remove_if([](std::pair<const int&,const MyData&> pair){
    return pair.first != 0;
});

remove_flags.erase(result.first,remove_flags.end());
data.erase(result.second,data.end());

但是动作不能在视图 zip 上操作,所以这不会编译。如果我将 ranges::actions::remove_if 切换到 ranges::views::remove_if,则会返回一个奇怪的视图对象,大概是该对象实际上并未对两个向量执行 std::remove 等效操作。

可以使用 contaner_to 但这会涉及副本,而且我不想为了方便而支付这种不必要的惩罚。 I've seen what I want accomplished in boost 其中实际的 zip 对迭代器可用于返回两个单独的删除结果。

这种模式在 Range-v3 中可行吗?

解决方法

对现有范围的急切操作是算法的领域。唯一的一点 这里棘手的一点是将迭代器恢复到向量中,因为 zip 没有给你一个直接的方法来获得它们。因此,改为使用新结束和范围开始之间的距离来恢复它们:

auto z = ranges::views::zip(remove_flags,data);
auto e = ranges::remove_if(z,[](auto&& r){ return r.first; });
data.erase(data.begin() + (e - z.begin()),data.end());
remove_flags.erase(remove_flags.begin() + (e - z.begin()),remove_flags.end());

Demo