Есть некоторый генератор, который выдает значения.
Его интерфейс описывается тремя функциями:
void Next(); // Сгенерировать значение
bool Done() const; // Значения закончились
T& Value(); // Текущее значение, movable
Получение значений в цикле выглядит так:
Generator<T> gen = ...;
gen.Next();
while (!gen.Done()) {
std::cout << gen.Value() << '\n';
gen.Next();
}
Как сделать итератор, чтобы можно было писать
for (T& x : gen) std::cout << x << '\n';
итератор должен поддержисать интерфейс InputIterator.
Итератор можно добавить через пару свободных функций begin и end.
#include <iterator>
#include <utility>
template<typename T>
struct GeneratorIterator {
// Поддержка std::iterator_traits:
using iterator_category = std::input_iterator_tag;
using value_type = T;
using difference_type = std::ptrdiff_t;
using pointer = value_type*;
using reference = value_type&;
using iterator = GeneratorIterator<T>; // Более короткое имя, для удобства
Generator<T>* g_; // Ссылка на генератор, он должен жить дольше итератора
GeneratorIterator(Generator<T>* g) : g_(g) {} // Конструктор
// Требования Iterator:
GeneratorIterator(const iterator&) = default; // CopyConstructible
iterator& operator=(const iterator&) = default; // CopyAssignable
~GeneratorIterator() = default; // Destructible
friend void swap(iterator& a, iterator& b) { std::swap(a.g_, b.g_); } // swappable
// Требования InputIterator:
friend bool operator==(const iterator& lhs, const iterator& rhs) { return lhs.g_ == rhs.g_; } // EqualityComparable
friend bool operator!=(const iterator& lhs, const iterator& rhs) { return !(lhs == rhs); } // a != b
reference operator*() const { // *a
return g_->Value();
}
pointer operator->() const { return std::addressof(**this); } // a->m
iterator& operator++() { // ++r
g_->Next();
if (g_->Done()) g_ = nullptr;
return *this;
}
struct proxy {
T value_;
proxy(T& value) : value_(std::move(value)) {}
reference operator*() { return value_; }
};
proxy operator++(int) { // (void)r++ , *r++
proxy old{**this};
++*this;
return old;
}
};
template<typename T>
GeneratorIterator<T> begin(Generator<T>& gen) {
GeneratorIterator<T> it{&gen};
return ++it;
}
template<typename T>
GeneratorIterator<T> end(Generator<T>&) {
return {nullptr};
}
Поддержка std::iterator_traits
обязательна для всех итераторов. Т.к. вспомогательный класс std::iterator
объявлен устаревшим в С++17, то мы не будем его использовать и напишем все 5 типов сами.
Требования Iterator это CopyConstructible, CopyAssignable, Destructible, swappable, а также *r
и ++r
которые перекрываются InputIterator.
Требования InputIterator это Iterator, EqualityComparable с дополнительным a != b
, также *a
, a->m
, ++r
, (void)r++
и *r++
.
Требование *r++
самое сложное, т.к. требует вспомогательного класса куда надо переместить значение. Если значение некопируемое, то от этого надо отказаться и оставить только поддержку (void)r++
.
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Как получить HWND окна при наведении на него курсора мыши С++ WinApi32 или Qt?
Например строковый литерал: "Hello, world!" не может стоять слева от оператора присваиванияТогда, как он может являться леводопустимым выражением?
Есть менюНужно, чтобы при нажатии на любой из пунктов меню - он подчеркивался черной линией
ЗдравствуйтеЯ чет торможу, не могу найти в документации как подключить jquery в Yii2