Перегрузочный итератор - PullRequest
0 голосов
/ 20 августа 2011

Обратите внимание, этот код был написан не мной. Иначе я бы не задавал этот вопрос. Полный кредит идет на Джерри Коффин . В любом случае код генерирует последовательность чисел путем перегрузки std :: iterator <>.

Сначала я опубликую код, а затем объясню, что я вижу. Если бы эксперт C ++ мог исправить меня, если я ошибаюсь, я был бы очень признателен.

Код

static const int N = 10;
template <class T>
class sequence : public std::iterator<std::forward_iterator_tag, T>
{
private:
    T val;
public:
    sequence(T init) : val(init) { }
    T operator *( ) { return val; }
    sequence &operator++( ) { ++val; return *this; }
    bool operator != ( const sequence &other ) { return val != other.val; }
};

void foo( )
{
    typedef std::vector<int> graph;
    graph id1( gen_seq(0), gen_seq( N ) );
    display( id1 );                             /* Not declared */
}

/* displays: 0 1 2 3 4 5 6 7 8 9 */

Итак, глядя на это, я вижу, что вы создаете класс, который содержит значение. Теперь мы передаем два из них в конструктор вектора, который может занять два итератора. Теперь каждый раз, когда конструктор вектора использует оператор ++ в «последовательности», он увеличивает значение внутри итератора. Технически, вы могли бы написать:

graph id1( gen_seq( 0 ), gen_seq( 0 ) );

и это будет генерировать ту же последовательность правильно? Или это оператор! =, Который проверяет, чтобы 0 не перешел на N. Любой вход в этом случае очень помог бы. Я только что закончил читать 3-е издание Страуструпа «Язык программирования С ++», в котором он коснулся итераторов, однако наследование от них не было большой темой и кое-чем, что я не до конца понимаю. Вроде как я бы выполнил все его упражнения, потому что я помню, как он несколько раз просил перегрузить итератор.

Ответы [ 2 ]

5 голосов
/ 20 августа 2011

Вы на самом деле не перегружаете итератор;вы пишете свой собственный итератор, который включает в себя перегрузку нескольких операторов.

Этот конструктор std::vector эффективно выглядит следующим образом:

template <typename ForwardIterator>
vector(ForwardIterator first, ForwardIterator last)
{
    for (ForwardIterator it = first; it != last; ++it)
        push_back(*it);
}

(На самом деле, он более сложный, чемон должен обрабатывать произвольно доступные диапазоны более эффективно, но для прямого итерируемого диапазона это то, что он делает.)

Как видите, этот конструктор выполняет три операции с вашим итератором: он разыменовывает его (*it), он увеличивает его (++it) и выполняет сравнение неравенства (it != last).Когда он выполняет каждую из этих вещей, он вызывает соответствующий оператор, который вы определили в своем пользовательском классе итератора.

graph id1( gen_seq( 0 ), gen_seq( 0 ) ); будет работать, но он не даст тот же результат: он оставит id1 пусто.Основываясь на объяснении в предыдущих параграфах, понимаете ли вы почему?

3 голосов
/ 20 августа 2011

Нет graph id1( gen_seq( 0 ), gen_seq( 0 ) ); будет генерировать вектор нулевого размера. Ваше второе объяснение с использованием != ближе. Может помочь, если вы поняли код ctor вектора. Это что-то вроде

template <class II>
vector::vector(II first, II last)
{
  while (first != last)
  {
    push_back(*first);
    ++first;
  }
}

Как видите, != используется, чтобы определить, когда прекратить добавлять элементы в вектор.

(По различным техническим причинам и причинам эффективности фактический код векторного вектора, вероятно, будет гораздо более сложным, чем этот, но вышеприведенное дает суть, поскольку оно применимо к вашему случаю).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...