How to implement something like std::copy_if but apply a function before inserting into a different container
Sure. There are a bunch of approaches.
Find a library with
transform_if
, likeboost
.Find a library with
transform_range
, which takes a transformation and range or container and returns a range with the value transformed. Compose this withcopy_if
.Find a library with
filter_range
like the above. Now, usestd::transform
with your filtered range.Find one with both, and compose filtering and transforming in the appropriate order. Now your problem is just copying (
std::copy
or whatever).Write your own back-inserter wrapper that transforms while inserting. Use that with
std::copy_if
.Write your own range adapters, like 2 3 and/or 4.
Write
transform_if
.
A quite general solution to your issue would be the following (working example):
#include <iostream>
#include <vector>
using namespace std;
template<typename It, typename MemberType, typename Cond, typename Do>
void process_filtered(It begin, It end, MemberType iterator_traits<It>::value_type::*ptr, Cond condition, Do process)
{
for(It it = begin; it != end; ++it)
{
if(condition((*it).*ptr))
{
process((*it).*ptr);
}
}
}
struct Data
{
int x;
int y;
};
int main()
{
// thanks to iterator_traits, vector could also be an array;
// kudos to @Yakk-AdamNevraumont
vector<Data> lines{{1,2},{4,3},{5,6}};
// filter even numbers from Data::x and output them
process_filtered(std::begin(lines), std::end(lines), &Data::x, [](int n){return n % 2 == 0;}, [](int n){cout << n;});
// output is 4, the only x value that is even
return 0;
}
It does not use STL, that is right, but you merely pass an iterator pair, the member to lookup and two lambdas/functions to it that will first filter and second use the filtered output, respectively.
I like your general solutions but here you do not need to have a lambda that extracts the corresponding attribute.
Clearly, the code can be refined to work with const_iterator
but for a general idea, I think, it should be helpful. You could also extend it to have a member function that returns a member attribute instead of a direct member attribute pointer, if you'd like to use this method for encapsulated classes.