What I want is this behavior: void change_if( ForwardIterator first, ForwardIterator last, UnaryPredicate test, UnaryOperation op )
Is the best way to achieve that just with a for loop? Or is there some STL magic I don't yet know?
This can be done without using boost but applying standard algorithm std::for_each
I do not advice to use boost for such simple tasks. It is simply a stupidy to include boost in your project that to perform such a simple task. You may use boost for such tasks provided that it is already included in your project.
std::for_each( first, last, []( const T &x ) { if ( test( x ) ) op( x ); } );
Or you can remove the qualifier const if you are going to change elements of the sequence
std::for_each( first, last, []( T &x ) { if ( test( x ) ) op( x ); } );
Sometimes when the whole range of a sequence is used it is simpler to use the range based for statement instead of an algorithm becuase using algorithms with lambda expressions sometimes makes code less readable
for ( auto &x : sequence )
{
if ( test( x ) ) op( x );
}
Or
for ( auto &x : sequence )
{
if ( test( x ) ) x = op( x );
}
The solution by Vlad from Moscow is the recommended approach for it's simplicity.
The "seemingly obious" use of the std::transform standard algorithm with a lambda:
std::transform(first, last, first, [](auto elem) {
return test(elem) ? op(elem) : elem;
});
actually leads to performance degradation because all elements will be assigned to, not just those satisfying the predicate. To only modify the predicated elements, one would also need something like boost::filter_iterator as mentioned in the answer by kiwi.
Note that I used C++14 syntax with the auto inside the lambda. For C++11, you would need something like decltype(*first) or iterator_traits<ForwardIterator>::value_type. And in C++98/03 you would both that and a hand made function object.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With