Использование ссылки. Поведение std :: generate должно быть эквивалентно:
template <class ForwardIterator, class Generator>
void generate ( ForwardIterator first, ForwardIterator last, Generator gen )
{
while (first != last) {
*first = gen();
++first;
}
}
Но когда я пытаюсь заполнить матрицу цифрами 0-99. Вместо этого я получаю 10 строк по 0-9. Почему это?
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
}
Вы также можете использовать std :: ref для предотвращения копирования объекта Generator:
generate(begin(v), end(v), std::ref(generator));
Поскольку ваш генератор копируется в соответствии с подписью
void generate ( ForwardIterator first, ForwardIterator last, Generator gen )
copied ----^^^^^^^^^^^^^
т.е. вы сохраняете свою собственную копию, также делает std::generate
. Каждый раз, когда вы передаете свой собственный, таким образом, немодифицированный generator
в std::generate
, т.е. Каждый раз, когда вы начинаете с версии с ее счетчиком 0
.
Вам нужно как-то сохранить счетчик в вашем функторе и поделиться им с использованием Generator
, например
struct Generator{
int *seq;
Generator(int &seq):seq(&seq){};
int operator()(){return (*seq)++;};
};
....
int seq = 0;
generate(begin(v), end(v), Generator(seq));
или эквивалентно
int seq = 0;
generate(begin(v), end(v), [&seq]() { return seq++; });
Если случай std::for_each
, вы передаете increment
лямбда-функции, которое принимает автоматическую переменную int я = 0;
по ссылке. Для каждого вызова for_each
создается новый increment
функтор, но i
не сбрасывается, а просто увеличивается; следовательно, вы видите, что значения являются непрерывными. Память лямбда-функции (i
) находится вне ее собственного домена, т.е. В основной функции родительской функции.
В случае вашей собственной функции generate
ресурс находится внутри структуры, т. Generator::seq
повторно инициализируется. Для каждого вызова generate
создается новый Генератор; его конструктор инициализирует seq
до 0, там путем сброса счетчика каждый раз.
#ifdef GENERATE
int i = 0; // lives in main
struct Generator {
int &seq;
Generator(int &i):seq(i) { }
int operator()() { return seq++; }
} generator(i);
#else
Это должно работать, поскольку часть памяти генератора теперь находится на более высоком уровне.