- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания C++17 STL Стандартная библиотека шаблонов - Яцек Галовиц
Шрифт:
Интервал:
Закладка:
Как это делается
В этом примере мы сконцентрируемся на реализации итератора, который генерирует числа на основе последовательности чисел Фибоначчи.
1. Чтобы иметь возможность вывести на экран числа Фибоначчи, включим соответствующий заголовочный файл:
#include <iostream>
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; }
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. Для того чтобы увидеть, как это делается, взглянем на другой пример, который решает именно эту задачу: обеспечивает совместимость ваших итераторов с категориями итераторов STL.
Представим, как эта задача решается с помощью итераторов. Во многих ситуациях у нас получится очень красивый код. Не волнуйтесь насчет производительности: компилятор без малейшего труда оптимизирует программу, отсекая стереотипный код, связанный с итераторами!
Чтобы не усложнять пример, мы ничего с ним не сделали, хотя могли опубликовать итератор Фибоначчи в виде библиотеки. В таком случае станет понятно, что у нее есть один недостаток: экземпляр fibit, который создается с помощью параметра конструктора, может быть использован только как конечный итератор, поскольку не содержит корректных значений Фибоначчи. Наша небольшая библиотека не предусматривает подобного варианта применения. Есть несколько способов это исправить.
□ Сделать конструктор fibit(size_t i_) закрытым и объявить, что класс fib_range является дружественным для класса fibit. Таким образом, пользователи могут применять его только корректным способом.
□ Задействовать особые символы, чтобы помешать пользователям разыменовать конечный итератор. Взгляните на пример, в котором мы делаем именно это: завершаем перебор диапазонов данных с помощью особых символов.
Перебор в обратную сторону с применением обратных адаптеров для итераторов
Иногда может быть полезно итерировать по диапазону данных не вперед, а назад. Основанный на диапазонах цикл for, а также все алгоритмы STL обычно итерируют по диапазонам данных, инкрементируя итераторы, однако перебор (итерирование) в обратную сторону требует выполнения операции декремента. Конечно, можно обернуть итераторы в слой, преобразующий операцию инкремента в операцию декремента. Но складывается впечатление, что у нас получится множество стереотипного кода на каждый тип, для которого мы собираемся поддерживать эту возможность.
Библиотека STL предоставляет полезный обратный адаптер для итератора, позволяющего задействовать итераторы подобным образом.
Как это делается
В этом примере мы будем разными способами применять обратные итераторы, чтобы показать варианты их использования.
1. Как обычно, включим некоторые заголовочные файлы:
#include <iostream>
#include <list>
#include <iterator>
2. Далее объявляем об использовании пространства имен std с целью сэкономить немного времени:
using namespace std;
3. Чтобы у нас появился объект, по которому мы сможем итерировать, создадим список, содержащий целые числа:
int main()
{
list<int> l {1, 2, 3, 4, 5};
4. Теперь выведем эти числа на экран в обратном порядке. Для этого проитерируем по списку благодаря функциям rbegin и rend класса std::list и выведем данные значения с помощью стандартного потока вывода, используя удобный адаптер ostream_iterator:
copy(l.rbegin(), l.rend(), ostream_iterator<int>{cout, ", "});
cout << 'n';
5. Если контейнер не предоставляет функций rbegin и rend, но хотя бы выдает двунаправленные итераторы, то поможет функция std::make_reverse_iterator. Она принимает обычные итераторы и преобразует их в обратные:
copy(make_reverse_iterator(end(l)),
make_reverse_iterator(begin(l)),
ostream_iterator<int>{cout, ", "});
cout << 'n';
}
6. Компиляция и запуск программы дадут следующий результат:
5, 4, 3, 2, 1,
5, 4, 3, 2, 1,
Как это работает
Преобразование обычного итератора в обратный