Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 227
sbi Avatar asked Jan 07 '17 23:01

sbi


People also ask

What does STD remove do?

std :: removeTransforms the range [first,last) into a range with all the elements that compare equal to val removed, and returns an iterator to the new end of that range. The function cannot alter the properties of the object containing the range of elements (i.e., it cannot alter the size of an array or a container).

What does Remove_if return C++?

C++ Algorithm remove_if() function is used to eliminate all the elements that satisfy a predicate from a given range [first, last) without disturbing the order of the remaining elements. This function cannot alter the size of the container. It returns an iterator to the new end of the range.


1 Answers

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.

like image 116
Barry Avatar answered Sep 30 '22 02:09

Barry