Генерация матрицы с помощью std :: generate

0

Использование ссылки. Поведение 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
}
Теги:
c++11
std

3 ответа

2
Лучший ответ

Вы также можете использовать std :: ref для предотвращения копирования объекта Generator:

generate(begin(v), end(v), std::ref(generator));
  • 0
    Вау, это должен быть ответ! Никогда не знал, спасибо :)
2

Поскольку ваш генератор копируется в соответствии с подписью

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++; });
  • 0
    Спасибо, это работает :), но ... после 2 изменений: int operator () () {return (* seq) ++;}; и генерировать (начало (v), конец (v), генератор (последовательность)); Не удалось отредактировать Ваш пост с менее чем 6 символами: P
  • 0
    Хорошо, спасибо за вашу коррекцию :)
2

Если случай 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

Это должно работать, поскольку часть памяти генератора теперь находится на более высоком уровне.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню