Captain Nemo
Captain Nemo

Reputation: 355

using std::transform the final vector remains empty

I am not using std::transform often, however I found it very useful and I am starting replacing some for loops with this algorithm.

What is wrong here? I want to keep all the elements of the vector vec that have code > 100. I would expect to have a new std::vector with 3 elements: 133, 144 and 155. But after the algorithm the size is 0. What is wrong?

 TEST_CASE("testing trasf1", "[tras1]") {

    std::vector<Test2> vec {
            {1,1},
            {3,3},
            {11,11},
            {12,12},
            {133,133},
            {19,19},
            {21,21},
            {22,22},
            {23,23},
            {144,144},
            {155,155}

    };

    std::vector<uint32_t> final_v {};
    final_v.reserve(vec.size());

    transform(begin(vec), end(vec), begin(final_v), [] (const Test2& elem) {
        if ( elem.getCode() > 100)
            return elem.getCode();
    });

    //REQUIRE(final.size() == 3);

    cout << final_v.size() << endl;

    for (const auto i : final_v) {
        cout << i << endl;
    }

}

Upvotes: 0

Views: 1366

Answers (2)

n314159
n314159

Reputation: 5085

Doing filter and transform in one operation:


template<class Container>
struct optional_inserter_iterator: std::back_insert_iterator //convenience
{
    using std::back_insert_iterator::*;
    optional_inserter_iterator(Container &c) : std::back_insert_iterator(c)
    {}

    optional_inserter_iterator & operator=(std::optional<Container::value_type> &&opt)
    {
        if(opt)
            std::back_insert_iterator::operator=(*std::move(opt))
        return *this;
    }
}

Use this in transform and let your lambda return an optional

(untested)

EDIT: There are some reasons not to inherit from std::back_insert_iterator. If someone is interested in a really correct version, I can do one.

Upvotes: 1

Anthony Williams
Anthony Williams

Reputation: 68591

transform doesn't insert elements into the output sequence, it just writes to the *iter and increments the iterator.

If you want to insert to the sequence, use std::back_inserter(final) as the output iterator.

Alternatively, call final.resize(vec.size()) first, to set the output vector to the correct size. Note that this will intialize the vector elements to zero, so for large vectors will incur a noticeable time overhead.

Upvotes: 4

Related Questions