Consider this code:
struct T
{
bool status;
UsefulData data;
};
std::forward_list<T> lst;
lst.remove_if([](T &x) -> bool { return x.status= !x.status; });
i.e. switching the status and removing inactive elements in one go.
According to cppreference the above code seems to be undefined behavior (emphasis mine):
template< class UnaryPredicate > void remove_if( UnaryPredicate p );
p- unary predicate which returns true if the element should be removed. The signature of the predicate function should be equivalent to the following:bool pred(const Type &a);The signature does not need to have
const &, but the function must not modify the objects passed to it. The typeTypemust be such that an object of typeforward_list<T,Allocator>::const_iteratorcan be dereferenced and then implicitly converted toType.
However, the current working draft seems to be less restrictive (N4659 [forwardlist.ops]):
void remove(const T& value) template <class Predicate> void remove_if(Predicate pred);Effects:
Erases all the elements in the list referred by a list iterator
ifor which the following conditions hold:*i == value(forremove()),pred(*i)istrue(forremove_if()). Invalidates only the iterators and references to the erased elements.Throws:
Nothing unless an exception is thrown by the equality comparison or the predicate.
Remarks:
Stable (20.5.5.7).
Complexity:
Exactly
distance(begin(), end())applications of the corresponding predicate.
Are there additional restrictions on predicates in other parts of the Standard?
I have tested the above code on a number of compilers and it compiles and seems to work as intended. Do I really need to transverse the list twice?