Things have changed dramatically in C++ in the past 15 years. In July 1994 Alexander Stepanov's proposal of a library that incorporates his ideas of generic programming received the final approval from the ANSI/ISO committee. This library that we conveniently call today the STL subsequently became a standard C++ library. The story of the STL is about as fascinating as the ideas behind it, and it definitely is worth the read.
The std::remove_if()
function that you found is just another reflection of this philosophy that became part of C++'s modern identity. In short, this is a generic function that will work on any container (sequence) of elements and with any(thing that acts like a) condition. To this effect, you must provide the function two things:
- a couple of iterators that delimit the range of elements you wish to work on;
- and a predicate that, when invoked on an element, returns true if the element is to be removed and false otherwise.
As it turns out, in this case the predicate you want is that of equality. And because it is such a common task to remove elements based on equality the standard also provides the std::remove()
function, which assumes an implicit equality predicate. Of course, you must make sure that elements can compare:
bool operator==(const MyClass& a, const MyClass& b)
{
// return true if the two are equal, and false otherwise.
}
We can then use our predicate to remove elements of type MyClass
:
std::remove(things.begin(), things.end(), *this); // if *this == elem
Recall that the standard function std::remove()
works on any container, even ones that haven't been created yet. Because every kind of container has its own way of removing elements, this function can't really perform the removal without knowing implementation details of the container it works on. So instead, the std::remove()
function swaps elements around such that the elements "removed" are at the end of the container. Then, it returns an iterator pointing at the first element of the consecutive elements "removed".
typedef std::list<MyClass>::iterator iter;
iter first_removed = std::remove(things.begin(), things.end(), *this);
Finally, we truly remove elements by calling the specific container's removal function, which works on a single position in the list or on a range of consecutive elements to remove:
things.erase(first_removed, things.end());
It is not uncommon to see this sort of code in a single line:
things.erase(std::remove(things.begin(), things.end(), *this),
things.end());
This all may seem overwhelming and complicated, but it has a few advantages. For one thing, this design of the standard library supports dynamic programming. It also allows the standard library to offer containers with very slim interfaces, as well as few free functions that work on many different kinds of containers. It allows you to quickly create a container and instantly gain all the features of the standard library to work with it. Alternatively, it allows you to quickly write a generic function that instantly works with all standard containers -- those written already and those not written yet.