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.

  1. Find a library with transform_if, like boost.

  2. Find a library with transform_range, which takes a transformation and range or container and returns a range with the value transformed. Compose this with copy_if.

  3. Find a library with filter_range like the above. Now, use std::transform with your filtered range.

  4. Find one with both, and compose filtering and transforming in the appropriate order. Now your problem is just copying (std::copy or whatever).

  5. Write your own back-inserter wrapper that transforms while inserting. Use that with std::copy_if.

  6. Write your own range adapters, like 2 3 and/or 4.

  7. 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.

Tags:

C++

Stl

C++14