- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания C++17 STL Стандартная библиотека шаблонов - Яцек Галовиц
Шрифт:
Интервал:
Закладка:
ostream_iterator<int> oit_comma {cout, ", "};
for (int i : v) { *oit_comma = i; }
cout << 'n';
10. Присвоение элементов итератору потока вывода для вывода их на экран — один из корректных способов использования итератора, но его создавали не для этого. Идея заключается в том, чтобы применить их вместе с алгоритмами. Самым простым алгоритмом является std::copy. Можно предоставить начальный и конечный итераторы вектора в качестве входного диапазона данных, а также итератор вывода потока в качестве итератора вывода. Алгоритм выведет все числа, содержащиеся в векторе. Сделаем это для обоих итераторов вывода, а затем сравним полученный результат с результатом работы циклов, написанных нами ранее:
copy(begin(v), end(v), oit);
cout << 'n';
copy(begin(v), end(v), oit_comma);
cout << 'n';
11. Помните функцию word_num, которая соотносит числа и строки — 1 с "one ", 2 с "two" и т.д.? Можно использовать для вывода данных и ее. Нужен только оператор вывода потока, имеющий шаблон, специализированный для типа string, поскольку мы больше не выводим целые числа. Вместо алгоритма std::copy станем использовать алгоритм std::transform, поскольку он позволяет применять функцию преобразования для каждого элемента входного диапазона до того, как эти элементы будут скопированы в выходной диапазон.
transform(begin(v), end(v),
ostream_iterator<string>{cout, " "},
word_num);
cout << 'n';
12. В последней строке выходных данных наконец используем структуру bork. Мы могли бы передать алгоритму std::transform функцию преобразования, но не стали. Вместо этого можно просто создать итератор потока вывода, который специализирован для типа bork в вызове std::copy. В результате экземпляры типа bork будут неявно создаваться на основе целых чисел, находящихся в диапазоне данных. Это даст интересные выходные данные:
copy(begin(v), end(v),
ostream_iterator<bork>{cout, "n"});
}
13. Компиляция и запуск программы дадут следующий результат. Первые две строки полностью идентичны следующим двум строкам, как мы и ожидали.
Далее мы получили «аккуратные» строки, содержащие текстовое написание чисел, разделенное пробелами, а после этого — множество строк bork!, для них был использован разделитель "n" вместо пробелов.
$ ./ostream_printing 12345
1, 2, 3, 4, 5,
12345
1, 2, 3, 4, 5,
one two three four five bork!
bork! bork!
bork! bork! bork!
bork! bork! bork! bork!
bork! bork! bork! bork! bork!
Как это работает
Мы увидели, что итератор std::ostream_iterator — всего лишь оболочка для функции вывода данных на экран, имеющая форму и синтаксис итератора. Инкрементирование этого итератора ни к чему не приводит. Его разыменование возвращает лишь прокси-объект, чей оператор присваивания перенаправляет аргумент в поток вывода.
Итераторы потока вывода, специализированные для типа T (например, ostream_ iterator<T>), работают для всех типов, для которых предоставлена реализация ostream& operator<<(ostream&, const T&).
Итератор ostream_iterator всегда пытается вызвать оператор << того типа, для которого он был специализирован, с помощью своего параметра шаблона. Он попробует неявно преобразовать типы, если это разрешено. Когда мы итерируем по диапазону элементов типа A, но копируем данные элементы в экземпляры типа output_iterator<B>, то код будет работать при условии, что тип A можно неявно преобразовать к типу B. Мы сделали именно это для структуры bork: экземпляр типа bork можно неявно получить из целочисленного значения. Как следствие, можно легко сгенерировать множество строк "bork! " на консоли пользователя.
Если неявное преобразование выполнить нельзя, можно провести его самостоятельно с помощью алгоритма std::transform, что мы и сделали в комбинации с функцией word_num.
Обратите внимание: как правило, разрешение неявного преобразования для пользовательских типов — плохой стиль программирования, поскольку такие преобразования являются распространенным источником ошибок, которые очень трудно найти. В нашем примере неявный конструктор скорее полезен, чем опасен, поскольку класс применяется только для вывода данных на экран.
Перенаправляем выходные данные в файл для конкретных разделов кода
Поток std::cout предоставляет удобный способ вывести на экран все, что мы хотим и когда хотим, поскольку его действительно просто использовать, легко расширять и получать к нему доступ глобально. Даже если мы желаем выводить особые сообщения, например сообщения об ошибках, которые нужно изолировать от обычных сообщений, то можем просто задействовать поток std::cerr. Он похож на cout, но выводит данные в стандартный канал ошибок, а не в стандартный канал для выходных данных.
При журналировании некоторой информации могут возникать и более сложные требования. Предположим, нужно перенаправить выходные данные, получаемые от некой функции, в файл или заглушить выходные данные, получаемые от функции, не изменяя ее саму. Возможно, это библиотечная функция и у нас нет доступа к ее исходному коду. Может быть, эта функция никогда не имела возможности записывать данные в файл, но мы хотим, чтобы она это делала.
Перенаправить выходные данные объектов потока можно. Далее мы рассмотрим, как это сделать очень простым и элегантным способом.
Как это делается
В этом примере мы реализуем вспомогательный класс, который решает задачу перенаправления потока и отмены такого перенаправления средствами конструкторов/деструкторов. А затем увидим, как это можно использовать.
1. В этот раз нужны только заголовочные файлы для потоков ввода/вывода и файлового потока. Кроме того, мы объявим об использовании пространства имен std по умолчанию:
#include <iostream>
#include <fstream>
using namespace std;
2. Реализуем класс, содержащий объект файлового потока и указатель на буфер потока. cout, представленный как объект потока, имеет внутренний буфер, который можно подменить. В процессе выполнения подобной подмены можно сохранить его исходное состояние, чтобы в будущем иметь возможность отменить это изменение. Мы могли бы найти его тип в справочном материале по С++, но также можем использовать decltype, чтобы узнать, какой тип возвращает конструкция cout.rdbuf(). Данный прием подходит не для всех ситуаций, но в нашем случае мы получим тип указателя:
class redirect_cout_region
{
using buftype = decltype(cout.rdbuf());
ofstream ofs;
buftype buf_backup;
3. Конструктор нашего класса принимает в