Where is erase_if?

Viewed 18377

I've got a container and would like to erase elements based on a predicate. erase_if sounds familiar, but I can't find it in C++. What's the name and where is it defined? I'd like to use it with a lambda in VS10.

7 Answers

MSVC does not yet implement C++20's std::erase_if from P1209R0 so, as a workaround, you can just copy the implementation for specific container from that paper somewhere to your code. GCC 9.1 and Clang 9.0 already have it.

namespace std {

// for std::string
template <class charT, class traits, class A, class Predicate>
void erase_if(basic_string<charT, traits, A>& c, Predicate pred) {
    c.erase(remove_if(c.begin(), c.end(), pred), c.end());
}

// for std::deque
template <class T, class A, class Predicate>
void erase_if(deque<T, A>& c, Predicate pred) {
    c.erase(remove_if(c.begin(), c.end(), pred), c.end());
}

// for std::vector
template <class T, class A, class Predicate>
void erase_if(vector<T, A>& c, Predicate pred) {
    c.erase(remove_if(c.begin(), c.end(), pred), c.end());
}

// for std::list
template <class T, class A, class Predicate>
void erase_if(list<T, A>& c, Predicate pred) {
    c.remove_if(pred);
}

// for std::forward_list
template <class T, class A, class Predicate>
void erase_if(forward_list<T, A>& c, Predicate pred) {
    c.remove_if(pred);
}

// for std::map
template <class K, class T, class C, class A, class Predicate>
void erase_if(map<K, T, C, A>& c, Predicate pred) {
    for (auto i = c.begin(), last = c.end(); i != last; )
        if (pred(*i))
            i = c.erase(i);
        else
            ++i;
}

// for std::multimap
template <class K, class T, class C, class A, class Predicate>
void erase_if(multimap<K, T, C, A>& c, Predicate pred) {
    for (auto i = c.begin(), last = c.end(); i != last; )
        if (pred(*i))
            i = c.erase(i);
        else
            ++i;
}

// for std::set
template <class K, class C, class A, class Predicate>
void erase_if(set<K, C, A>& c, Predicate pred) {
    for (auto i = c.begin(), last = c.end(); i != last; )
        if (pred(*i))
            i = c.erase(i);
        else
            ++i;
}

// for std::multiset
template <class K, class C, class A, class Predicate>
void erase_if(multiset<K, C, A>& c, Predicate pred) {
    for (auto i = c.begin(), last = c.end(); i != last; )
        if (pred(*i))
            i = c.erase(i);
        else
            ++i;
}

// for std::unordered_map
template <class K, class T, class H, class P, class A, class Predicate>
void erase_if(unordered_map<K, T, H, P, A>& c, Predicate pred) {
    for (auto i = c.begin(), last = c.end(); i != last; )
        if (pred(*i))
            i = c.erase(i);
        else
            ++i;
}

// for std::unordered_multimap
template <class K, class T, class H, class P, class A, class Predicate>
void erase_if(unordered_multimap<K, T, H, P, A>& c, Predicate pred) {
    for (auto i = c.begin(), last = c.end(); i != last; )
        if (pred(*i))
            i = c.erase(i);
        else
            ++i;
}

// for std::unordered_set
template <class K, class H, class P, class A, class Predicate>
void erase_if(unordered_set<K, H, P, A>& c, Predicate pred) {
    for (auto i = c.begin(), last = c.end(); i != last; )
        if (pred(*i))
            i = c.erase(i);
        else
            ++i;
}

// for std::unordered_multiset
template <class K, class H, class P, class A, class Predicate>
void erase_if(unordered_multiset<K, H, P, A>& c, Predicate pred) {
    for (auto i = c.begin(), last = c.end(); i != last; )
        if (pred(*i))
            i = c.erase(i);
        else
            ++i;
}

} // namespace std

Actually there exists a method called erase_if in the Boost library for pointer containers.

With the new C++ 20 format you can use it like this:

vector<int> vec {1,2,3,4,5};
auto no_of_removed_elements = std::erase_if(vec,[](const int a){return a==5;});

Link to the reference.

Related