Can I abuse a predicate to perform operations on the elements before remove_if removes them?

292 Views Asked by At

I have a std::list of objects. The list is sorted and must stay that way. I need to find those objects that satisfy a certain criterion (I have a predicate for this), pass them to a function, and then delete the objects from the list.

It's not too hard to write a loop that calls std::find_if(), invokes the operation on its result (if any), calls list.erase(), and passes the result of that as begin iterator to the next call to std::find_if(). IME, however, people find such code harder to read than it is to write it.

So I would preferably employ some algorithm(s) from the std lib rather than writing my own loop.

One idea was to (ab)use std::list<>::remove_if(): Invoke the operation on the elements that match _from the predicate, before it returns true, so that the list will delete the elements. Would that be standard-conforming? (The items themselves won't be changed, only data they refer to.)

Or can you come up with a better solution? (Again, the main objective is to make this easy to read and understand.) Maybe it's because I just ran into it, but to me it seems this might not be an uncommon usage pattern for a sequence of objects.

Note: For the time being , we're firmly stuck in C++03 land. :-/ C++11/14/17 solutions would be interesting and thus welcome, but I do need something that works with C++03.

1

There are 1 best solutions below

2
On BEST ANSWER

Can I abuse a predicate to perform operations on the elements before remove_if removes them?

Yes. There's nothing in the standard specification that requires the predicate to be a pure function. So this C++11 solution would be perfectly fine:

my_list.remove_if([f, pred](Elem const& e){
    if (pred(e)) {
        f(e);
        return true;
    }
    return false;
});

Nothing even requires the predicate to ever return true. You can even use remove_if as a poor man's, unnecessarily confusing for_each:

my_list.remove_if([f](Elem const& e){
    f(e);
    return false;
});

That's pointless and inefficient, but it's definitely standards conforming.

You can write the equivalent in C++03 as a function object. Whether or not you find that easier to read than the for loop is a matter of opinion. But it's not wrong.