5. При инкрементировании итератор (++it
) переместится на следующее число Фибоначчи. Эта функция содержит тот же код, что и реализация функции Фибоначчи, основанная на цикле:
fibit& operator++() {
const size_t old_b {b};
b += a;
a = old_b;
++i;
return *this;
}
6. При использовании в цикле инкрементированный итератор сравнивается с конечным итератором, для чего следует реализовать оператор !=
. Мы выполняем сравнение только на том шаге, на котором в данный момент находятся итераторы Фибоначчи, что позволяет проще определить конечный итератор, скажем, для шага 1000000
, поскольку не нужно выполнять трудоемкие вычисления этого довольно большого числа Фибоначчи
bool operator!=(const fibit &o) const { return i != o.i; }
};
7. Чтобы иметь возможность использовать итератор Фибоначчи в основанном на диапазоне цикле for
, реализуем класс диапазона заранее. Назовем его fib_range
. Его конструктор будет принимать один параметр, который скажет, насколько далеко нужно проитерировать по диапазону данных:
class fib_range
{
size_t end_n;
public:
fib_range(size_t end_n_)
: end_n{end_n_}
{}
8. Функции begin
и end
возвращают итераторы, которые указывают на позиции F(0)
и F(end_n)
:
fibit begin() const { return fibit{}; }
fibit end() const { return fibit{end_n}; }
};
9. О’кей, теперь забудем о реализации стереотипного кода, связанного с итераторами. Теперь у нас есть вспомогательный класс, который аккуратно скрывает детали реализации! Выведем на экран первые десять чисел Фибоначчи.
int main()
{
for (size_t i : fib_range(10)) {
std::cout << i << ", ";
}
std::cout << '\n';
}
10. Компиляция и запуск программы дадут следующий результат:
1, 1, 2, 3, 5, 8, 13, 21, 34, 55,
Дополнительная информация
Использование этого итератора совместно с библиотекой STL предполагает, что он должен поддерживать класс std::iterator_traits
. Для того чтобы увидеть, как это делается, взглянем на другой пример, который решает именно эту задачу:
Чтобы не усложнять пример, мы ничего с ним не сделали, хотя могли опубликовать итератор Фибоначчи в виде библиотеки. В таком случае станет понятно, что у нее есть один недостаток: экземпляр fibit
, который создается с помощью параметра конструктора, может быть использован только как конечный итератор, поскольку не содержит корректных значений Фибоначчи. Наша небольшая библиотека не предусматривает подобного варианта применения. Есть несколько способов это исправить.
□ Сделать конструктор fibit(size_t i_)
закрытым и объявить, что класс fib_range
является дружественным для класса fibit
. Таким образом, пользователи могут применять его только корректным способом.
□ Задействовать особые символы, чтобы помешать пользователям разыменовать конечный итератор. Взгляните на пример, в котором мы делаем именно это:
Перебор в обратную сторону с применением обратных адаптеров для итераторов
Иногда может быть полезно итерировать по диапазону данных не вперед, а for
, а также все алгоритмы STL обычно итерируют по диапазонам данных, инкрементируя итераторы, однако перебор (итерирование) в обратную сторону требует выполнения операции
Библиотека STL предоставляет полезный
Как это делается
В этом примере мы будем разными способами применять обратные итераторы, чтобы показать варианты их использования.
1. Как обычно, включим некоторые заголовочные файлы:
#include
#include
#include
2. Далее объявляем об использовании пространства имен std
с целью сэкономить немного времени: