Why is a convenience helper for the erase-remove-idiom not provided by the standard?
Asked Answered
O

1

4

Removing items from a collection in the STL requires a technique used so often that is has become an idiom: the erase-remove-idiom

One of the most common usages of this idiom is to remove an item of type T from a vector<T>

std::vector<Widget> widget_collection;
Widget widget;

widget_collection.erase(
    std::remove(widget_collection.begin(), widget_collection.end(), widget), 
    widget_collection.end());

This is obviously very verbose, and violates the DRY principle - the vector in question is required 4 times there.

So my question is why does the standard not provide a convenience helper?

Something like

widget_collection.erase_remove(widget);

or

std::erase_remove(widget_collection, widget);

This could obviously be extended to

widget_collection.erase_remove_if(widget, pred);

etc...

Oberhausen answered 4/11, 2015 at 13:48 Comment(4)
You cold always write your own.Antonetteantoni
I have! :) I just thought it would be a fairly simple addition to <algorithm> so all could benefit from itOberhausen
@SteveLorimer I have too. Do you specialize on list<>?Holley
@Holley I don't, because I just use list::erase. It could certainly be made more generic. I'm glad N4273 is accepted as it is definitely more elegant and has wider coverage than my implementation!Oberhausen
U
6

This issue is covered by proposal N4009: Uniform Container Erasure which says:

This is a proposal to add erase_if(container, pred), making it easier to eliminate unwanted elements correctly and efficiently.

[...]

It's surprisingly difficult to eliminate unwanted elements from a container, given a predicate that distinguishes "bad" elements from "good" elements.

One of the STL's major strengths is that all of its containers have similar interfaces - they have many functions in common and they follow the same conventions. When container interfaces vary, fundamental differences between their data structures are responsible. Even those differences can often be ignored, thanks to the STL's container-iterator-algorithm design.

and also notes:

The correct response is to use the erase-remove idiom, which is non-obvious and must be taught instead of discovered (it's called an "idiom" for a reason).

the latest version N4273: Uniform Container Erasure (Revision 2) looks like it was adopted. It is part of Extensions for Library Fundamentals V2 . Also see the cppreference section for C++ standard libraries extensions, version 2.

The head revision(version 6.0.0) of gcc available on Wandbox has an implementation of this header (see it live):

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

int main()
{
    std::vector<int> v1 = {1,2,3,4,5,6} ;

    std::experimental::erase_if( v1, [] (const int &x ) { return x < 4; } ) ;

    for( const auto & v : v1 )
    {
        std::cout << v << ", " ;
    }
    std::cout << "\n" ;
}

This code also work on webcompiler which seems to confirm T.C.'s suggestion that this also shipped with MSVC 2015.

Ultrasonics answered 4/11, 2015 at 14:2 Comment(2)
Thanks! Do you know where I can find information on the release schedules for these extensions? Are they part of C++14?Oberhausen
@SteveLorimer no, I have not been paying as much attention to the libraries work as the core working group. But here STL says likely C++17 for his proposal.Ultrasonics

© 2022 - 2024 — McMap. All rights reserved.