Reputation: 128
Using reference. The behavior of std::generate should be equivalent to:
template <class ForwardIterator, class Generator>
void generate ( ForwardIterator first, ForwardIterator last, Generator gen )
{
while (first != last) {
*first = gen();
++first;
}
}
But when I try to fill matrix with 0-99 numbers. Instead I get 10 rows of 0-9. Why is that?
std::vector< std::vector<int> > m;
#ifdef GENERATE
struct Generator{
int seq;
Generator():seq(0){};
int operator()(){return seq++;};
} generator;
#elif defined FOR_EACH
int i = 0;
auto increment = [&i](int &a){a = i++;};
#endif
int x = 10, y = 10;
m.resize(x);
for(auto &v : m)
{
v.resize(y);
#ifdef GENERATE
generate(begin(v), end(v), generator);
#elif defined FOR_EACH
for_each(begin(v),end(v), increment);
#endif
}
Upvotes: 0
Views: 247
Reputation: 39109
Because your generator is copied according to the signature
void generate ( ForwardIterator first, ForwardIterator last, Generator gen )
copied ----^^^^^^^^^^^^^
i.e. you keep your own copy, std::generate
does as well. Every time you pass your own, thus unmodified generator
into std::generate
, i.e. each time you begin with a version that has its counter 0
.
You need to somehow preserve the counter in your functor and share it across uses of Generator
, e.g.
struct Generator{
int *seq;
Generator(int &seq):seq(&seq){};
int operator()(){return (*seq)++;};
};
....
int seq = 0;
generate(begin(v), end(v), Generator(seq));
or equivalently
int seq = 0;
generate(begin(v), end(v), [&seq]() { return seq++; });
Upvotes: 2
Reputation: 12948
You may also use std::ref to prevent copying of Generator object:
generate(begin(v), end(v), std::ref(generator));
Upvotes: 3
Reputation: 33004
If case of std::for_each
, you pass the lambda function increment
which takes the automatic variable int i = 0;
by reference. For every invocation for_each
it creates a new increment
functor, but i
is not reset but just incremented; hence you see the values being continuous. The memory of the lambda function (i
) is outside its own domain i.e. in the parent function main.
In case of your own generate
function, the resource is within the structure i.e. Generator::seq
is reinitialized. For every invocation of generate
, a new Generator is created; its constructor initializes seq
to 0, there by resetting the count every time.
#ifdef GENERATE
int i = 0; // lives in main
struct Generator {
int &seq;
Generator(int &i):seq(i) { }
int operator()() { return seq++; }
} generator(i);
#else
This should work, since the memory part of the Generator is now at a higher level.
Upvotes: 2