I wanted to replace the loop with an algorithm in the following code
int numbers[] = { ... };
vector<int> output;
for( int* it = numbers+from; it != numbers+to ; ++it )
{
int square = func( *it );
if( predicate(square) )
{
output.push_back(square);
}
}
The program is meant to transform the values and copy them to a destination if a condition occurs.
std::copy_if
because that would not apply a transformation.std::transform
because that lacks a predicatetransform_copy_if()
, because of the intermediate copy of the transformed variable.It looks like my only hope is to create a conditional_back_insert_iterator
. Then I could have a pretty decent call like:
int numbers[] = { ... };
vector<int> output;
std::transform(numbers+from, numbers+to,
conditional_back_inserter(predicate, output),
func);
Is this solution the best way to treat such cases ? I couldn't even google for conditional inserters, so I am worried I'm on the wrong path.
I could also imagine that I could implement an alternative solution such as
std::copy_if( transform_iterator<func>(numbers+from),
transform_iterator<func>(numbers+to),
back_inserter(output) );
(which reminds me of an example of *filter_iterators* in boost) but that does not offer readability.
I think creating your own iterator is the way to go:
#include <iostream>
#include <vector>
#include <iterator>
#include <functional>
template<class T>
class conditional_back_insert_iterator
: public std::back_insert_iterator<std::vector<T>>
{
private:
using Base = std::back_insert_iterator<std::vector<T>>;
using Container = std::vector<T>;
using value_type = typename Container::value_type;
public:
template<class F>
conditional_back_insert_iterator(Container& other, F&& pred)
: Base(other), c(other), predicate(std::forward<F>(pred))
{ }
conditional_back_insert_iterator<T>& operator*()
{ return *this; }
conditional_back_insert_iterator<T>&
operator=(const value_type& val) const
{
if (predicate(val))
c.push_back(val);
return *this;
}
conditional_back_insert_iterator<T>&
operator=(value_type&& val) const
{
if (predicate(val))
c.push_back(std::move(val));
return *this;
}
private:
Container& c;
std::function<bool (const value_type&)> predicate;
};
template<
class Container,
class F,
class value_type = typename Container::value_type
>
conditional_back_insert_iterator<value_type>
conditional_back_inserter(Container& c, F&& predicate)
{
return conditional_back_insert_iterator<value_type>(c, std::forward<F>(predicate));
}
int main()
{
std::vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9};
std::vector<int> to;
auto is_even = [] (int x) { return (x % 2) == 0; };
std::copy(v.begin(), v.end(), conditional_back_inserter(to, is_even));
}
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