Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

STL Algorithm that Takes a Test and Mutate Function

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?

like image 701
Jonathan Mee Avatar asked Sep 11 '26 19:09

Jonathan Mee


2 Answers

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 );
}
like image 145
Vlad from Moscow Avatar answered Sep 14 '26 08:09

Vlad from Moscow


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.

like image 41
TemplateRex Avatar answered Sep 14 '26 09:09

TemplateRex