Адаптер istream_iterator
тоже довольно удобен. Он подходит для любого объекта std::istream
(который может представлять собой стандартный поток ввода или файлы) и будет пытаться преобразовывать полученные данные в соответствии с параметром шаблона. В этом примере мы использовали конструкцию std::istream_iterator
, получающую из потока ввода целые числа.
Как правило, мы не знаем длину потока. Это оставляет открытым вопрос: куда указывает
std::ostream_iterator
Адаптер ostream_iterator
аналогичен адаптеру istream_iterator
, но работает по обратному принципу: не принимает токены ,
" или символ перехода на новую строку.
Реализуем алгоритмы с помощью итераторов
Итераторы обычно итерируют, ++it
) и возвращать это значение при разыменовании (*it
).
В данном разделе мы рассмотрим этот принцип, реализовав функцию, выводящую на экран последовательность чисел Фибоначчи с помощью итераторов. Такая функция рекурсивно определяется следующим образом: F(n) = F(n-1)+F(n-2)
. Она начинается со стартовых значений F(0) = 0
и F(1) = 1
. Это приводит к появлению такой последовательности чисел:
□ F(0) = 0;
□ F(1) = 1;
□ F(2) = F(1)+F(0) = 1;
□ F(3) = F(2)+F(1) = 2;
□ F(4) = F(3)+F(2) = 3;
□ F(5) = F(4)+F(3) = 5;
□ F(6) = F(5)+F(4) = 8;
□ ... и т.д.
Если мы реализуем это в форме вызываемой функции, которая возвращает значение Фибоначчи для любого числа n, то получим рекурсивную функцию, вызывающую саму себя, или цикл. Такой результат приемлем, но что, если мы напишем программу, принимающую числа Фибоначчи по некоему шаблону одно за другим? У нас есть два варианта: либо выполнять все рекурсивные вызовы для каждого числа Фибоначчи (это, по сути, растрата вычислительного времени), либо сохранять два последних числа во временных переменных и использовать их для вычисления следующего. Во втором случае придется
size_t a {0};
size_t b {1};
for (size_t i {0}; i < N; ++i) {
const size_t old_b {b};
b += a;
a = old_b;
// сделаем что-нибудь с b, текущим числом Фибоначчи
}
Итераторы позволяют решить задачу оригинальным способом. Можно обернуть шаги, которые нужно сделать в реализации, основанной на цикле функции Фибоначчи, в префиксный оператор ++
Как это делается
В этом примере мы сконцентрируемся на реализации итератора, который генерирует числа на основе последовательности чисел Фибоначчи.
1. Чтобы иметь возможность вывести на экран числа Фибоначчи, включим соответствующий заголовочный файл:
#include
2. Определим итератор Фибоначчи, fibit
. Он будет содержать член i
, в котором будет сохраняться индекс позиции в последовательности Фибоначчи, а также члены a
и b
, в которых будут храниться два последних значения Фибоначчи. При вызове конструктора по умолчанию итератор Фибоначчи инициализируется значениями F(0)
.
class fibit
{
size_t i {0};
size_t a {0};
size_t b {1};
3. Далее определим стандартный конструктор и конструктор, который позволит инициализировать итератор любым этапом вычисления чисел Фибоначчи:
public:
fibit() = default;
explicit fibit(size_t i_)
: i{i_}
{}
4. Разыменование итератора (*it
) вернет текущее число Фибоначчи на данном шаге:
size_t operator*() const { return b; }