Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

return value iterator of std::generate_n, what can you do with it?

Out of curiosity!

What can you do with the returning iterator of std::generate_n?

Return value :

Iterator one past the last element assigned if count > 0, first otherwise.

    std::vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    auto iterator = std::generate_n(std::back_inserter(v), 10, [&]() {return j++;});
    std::cout << "type: " << typeid(iterator).name() << '\n';
/*
    for (iterator = v.begin(); iterator< v.end(); iterator++){
        std::cout << *iterator << " " << endl;
    }
*/
    for(auto a : v)
        std::cout << a << " ";
    std::cout << std::endl;

Output:

type: St20back_insert_iteratorISt6vectorIiSaIiEEE
1 2 3 4 5 6 7 8 9 10 0 1 2 3 4 5 6 7 8 9 

iterator shows a few member functions, but they are mostly operators.

like image 998
NaturalDemon Avatar asked Dec 14 '22 08:12

NaturalDemon


2 Answers

It's an output iterator. You an use it like any output iterator. It is the same type that you pass as the first argument - even same value in case nothing is generated.

Back inserter isn't exactly ideal example for this because it doesn't really care about the position (fun fact: incrementing a back inserter does nothing). A more important use case is an iterator to an existing element in which case we care about which elements we are writing over.

An extended example, using two different generators for the same container:

auto generator1 = [&]() { return j++; };
auto generator2 = [&]() { return j--; };
auto it = v.begin();
it = std::generate_n(it, 5, generator1);
it = std::generate_n(it, 5, generator2);
like image 111
eerorika Avatar answered Dec 29 '22 10:12

eerorika


Suppose you want to generate elements for the first half and then use a different generator for the second half, then you can simply write:

#include <vector>
#include <algorithm>
#include <iostream>

int main() {
    int j = 0;
    std::vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    auto iterator = std::generate_n(v.begin(), 5, [&]() {return j++;});
    
    std::generate_n(iterator,5,[&](){ return j;});
    
    
    for (auto i : v){
        std::cout << i << " ";
    }
}

Without manually calculating the iterator that points to the element after the ones from the first call.

Output is:

0 1 2 3 4 5 5 5 5 5 

In your example iterator is just an iterator one past the last element of the vector and brings no big advantage because it is the same as v.end().

like image 20
463035818_is_not_a_number Avatar answered Dec 29 '22 12:12

463035818_is_not_a_number