是否有比 std::remove_if 更好的替代方法来从向量中删除元素?

Is there a better alternative to std::remove_if to remove elements from a vector?

std::vector 或其他容器中删除具有特定 属性 的元素的任务适合于函数式风格的实现:为什么要为循环、内存重新分配和正确移动数据而烦恼?

然而,在 C++ 中执行此操作的标准方法似乎是以下成语:

std::vector<int> ints;
...
ints.erase(
    std::remove_if(ints.begin(), 
                   ints.end(),
                   [](int x){return x < 0;}),
    ints.end());

此示例从整数向量中删除所有小于零的元素。

我觉得不仅丑,而且容易误用。很明显 std::remove_if 不能改变向量的大小(正如它的名字所暗示的那样),因为它只传递迭代器。但是许多开发人员,包括我自己,一开始并没有明白这一点。

那么有没有更安全、更优雅的方法来实现这一点?如果不是,为什么?

I find it not only ugly but also easy to use incorrectly.

别担心,一开始我们都这样做了。

It is clear that std::remove_if cannot change the size of the vector (as its name would suggest) because it only gets iterators passed. But many developers, including myself, don't get that in the beginning.

同上。这让每个人都感到困惑。那些年前它可能不应该被称为 remove_if。事后看来,嗯?

So is there a safer and hopefully more elegant way to achieve this?

没有

If not, why?

因为这是最安全、最优雅的方式,可以在从容器中删除项目时保持性能,其中删除项目会使迭代器失效。

期待:

Anything I can do?

是的,把这个成语包装成一个函数

template<class Container, class F>
auto erase_where(Container& c, F&& f)
{
    return c.erase(std::remove_if(c.begin(), 
                                  c.end(),
                                  std::forward<F>(f)),
                   c.end());    
}

激励示例中的调用变为:

auto is_negative = [](int x){return x < 0;};
erase_where(ints, is_negative);

erase_where(ints, [](int x){return x < 0;});

这将很快通过 std::experimental::erase_if 算法在支持 C++17 的编译器中可用:

#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
#include <experimental/vector>

int main()
{
    std::vector<int> ints { -1, 0, 1 };   
    std::experimental::erase_if(ints, [](int x){
        return x < 0;
    });
    std::copy(ints.begin(), ints.end(), std::ostream_iterator<int>(std::cout, ","));
}

Live Example 打印 0,1