C++. Сборник рецептов - [109]

Шрифт
Интервал

>}

Вывод примера 7.11 может выглядеть так.

>Введите несколько строк: z x y a b с

>^Z

>z, x, y, a, b, с,

Обсуждение

Потоковый итератор — это итератор, который основан на потоке, а не на диапазоне элементов контейнера, и позволяет рассматривать поток как итератор ввода (читать из разыменованного значения и увеличивать итератор) или итератор вывода (аналогично итератору ввода, но для записи в разыменованное значение вместо чтения из него). Это облегчает чтение значений (особенно строк) из потока, что делается в нескольких других примерах этой главы, и запись значений в поток, что делается в примере 7.11. Я знаю, что этот рецепт посвящен записи диапазона в поток, но позвольте мне немного отойти от этой задачи и, поскольку я использую потоковые итераторы во многих примерах этой главы, объяснить, что это такое.

В примере 7.11 показаны три ключевые части >istream_iterator. Первая часть — это создание >istream_iterator, указывающего на начало потокового ввода. Это делается вот так.

>istream_iterator start(cin);

В результате создается итератор с именем >start, который указывает на первый элемент входной последовательности, точно так же, как >vec.begin (>vec — это >vector) возвращает итератор, который указывает на первый элемент в векторе. Аргумент шаблона >string говорит >istream_iterator, что элементы в этой последовательности имеют тип >string. Аргумент конструктора >cin — это входной поток, из которого производится чтение. Однако это абстракция, так как первого элемента не существует, поскольку из >cin еще ничего прочитано не было. Это произойдет несколько позже.

Вторая часть итератора входного потока — это маркер конца, который создается вот так.

>istream_iterator end;

Стандартные контейнеры используют специальное значение «один после конца», указывающее на точку, где должно остановиться использование алгоритма. Так как итератор входного потока не имеет в памяти последнего элемента, он для создания логической конечной точки, представляющей точку остановки использования алгоритма, использует конструктор без аргументов.

Последней частью методики использования >istream_iterator является его использование для извлечения значений. Удобным способом вытащить в контейнер все значения, введенные в поток, является использование конструктора диапазона контейнера. Например, если создать >vector с двумя итераторами, то его конструктор скопирует в контейнер все элементы диапазона, определяемого итераторами. Если передать только что созданные итераторы >start и >end, то это будет выглядеть так.

>vector v(start, end);

Именно здесь происходит чтение значений из потока. При создании >v он начинает со >start и перебирает все значения, пока не достигнет >end. Каждый раз, когда >v читает из >*start, происходит нечто эквивалентное такому вызову >cin.

>cin >> v[i]; // v - это vector

Другими словами, следующее значение, извлекаемое из >cin, преобразуется в >string и вставляется в >vector.

При использовании >cin как входного потока маркер конца файла, который отмечает конец потока, определяется используемой платформой. В Windows для завершения входного потока требуется нажать на Enter, Ctrl-Z, Enter. Чтобы увидеть, что требуется сделать на вашей платформе, проведите эксперименты, но велика вероятность, что будут использоваться эти же клавиши.

Итераторы выходных потоков ведут себя аналогично итераторам потоков ввода. В примере 7.11 я копирую значения из своего >vector в >cout, создав для этого >ostream_iterator, который указывает на >cout, следующим образом.

>copy(v.begin(), v.end(), ostream_iterator(cout, ", "));

Аргумент шаблона >ostream_iterator говорит, что записываемые элементы будут иметь тип >string. Первый аргумент конструктора >ostream_iterator — это поток, в который будет производиться запись (и который может быть любым потоком вывода, включая >ofstream и >ostringstream), а второй это используемый разделитель. Это дает удобный способ выводить диапазон значений на стандартный вывод, что я часто делаю при отладке.

Если требуется дополнительное управление внешним видом вывода, например вывод последовательности в квадратных или фигурных скобках или отсутствие последнего разделителя в конце последовательности, то это потребует всего нескольких дополнительных строк кода. Пример 7.12 показывает тело >printContainer и >printRange, первая из которых используется в примерах этой главы.

Пример 7.12. Написание собственной функции печати

>#include

>#include

>#include

>#include

>#include


>using namespace std;


>template

>void printContainer(const C& c, char delim = ',', ostream& out = cout) {

> printRange(c.begin(), c.end(), delim, out);

>}


>template

>void printRange(Fwd first, Fwd last, char delim = ',', ostream& out = cout) {

> out << "{";

> while (first != last) {

>  out << *first;

>  if (++first != last)

>   out << delim << ' ';

> }

> out << "}" << endl;

>}


>int main() {

> cout << "Введите набор строк: ";

> istream_iterator start(cin);

> istream_iterator end;

> vector v(start, end);

> printContainer(v);

> printRange(v.begin(), v.end(), ';', cout);


Рекомендуем почитать
Изучаем Java EE 7

Java Enterprise Edition (Java EE) остается одной из ведущих технологий и платформ на основе Java. Данная книга представляет собой логичное пошаговое руководство, в котором подробно описаны многие спецификации и эталонные реализации Java EE 7. Работа с ними продемонстрирована на практических примерах. В этом фундаментальном издании также используется новейшая версия инструмента GlassFish, предназначенного для развертывания и администрирования примеров кода. Книга написана ведущим специалистом по обработке запросов на спецификацию Java EE, членом наблюдательного совета организации Java Community Process (JCP)


Pro Git

Разработчику часто требуется много сторонних инструментов, чтобы создавать и поддерживать проект. Система Git — один из таких инструментов и используется для контроля промежуточных версий вашего приложения, позволяя вам исправлять ошибки, откатывать к старой версии, разрабатывать проект в команде и сливать его потом. В книге вы узнаете об основах работы с Git: установка, ключевые команды, gitHub и многое другое.В книге рассматриваются следующие темы:основы Git;ветвление в Git;Git на сервере;распределённый Git;GitHub;инструменты Git;настройка Git;Git и другие системы контроля версий.


Java 7

Рассмотрено все необходимое для разработки, компиляции, отладки и запуска приложений Java. Изложены практические приемы использования как традиционных, так и новейших конструкций объектно-ориентированного языка Java, графической библиотеки классов Swing, расширенной библиотеки Java 2D, работа со звуком, печать, способы русификации программ. Приведено полное описание нововведений Java SE 7: двоичная запись чисел, строковые варианты разветвлений, "ромбовидный оператор", NIO2, новые средства многопоточности и др.


Создаем порт для FreeBSD своими руками. Часть II

Система сборки программ, используемая во FreeBSD, имеет значительно большие возможности, чем те, которые мы задействовали. Какие это возможности и как их использовать в своих портах?


Питон — модули, пакеты, классы, экземпляры

Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.


Как пасти котов. Наставление для программистов, руководящих другими программистами

«Как пасти котов» – это книга о лидерстве и руководстве, о том, как первое совмещать со вторым. Это, если хотите, словарь трудных случаев управления IT-проектами. Программист подобен кошке, которая гуляет сама по себе. Так уж исторически сложилось. Именно поэтому так непросто быть руководителем команды разработчиков. Даже если вы еще месяц назад были блестящим и дисциплинированным программистом и вдруг оказались в роли менеджера, вряд ли вы знаете, с чего надо начать, какой выбрать стиль руководства, как нанимать и увольнять сотрудников, проводить совещания, добиваться своевременного выполнения задач.