При написании собственного алгоритма для работы с диапазонами (т.е. со стандартными контейнерами) вы должны работать с аргументами-итераторами, а не с аргументами-контейнерами. У вас может возникнуть желание объявить copyIf
copyIf
появится зависимость от методов контейнеров begin
и end
, которые дадут требуемый диапазон, и возвращаемый тип будет зависеть от типа контейнера, используемого в качестве выходного. Это означает, что использование в copyIf
нестандартных диапазонов, таких как встроенные массивы или собственные контейнеры, работать не будет. Именно по этим и некоторым другим причинам все стандартные алгоритмы оперируют с диапазонами.Наконец, если вы пишете свой алгоритм, дважды убедитесь, что стандартные алгоритмы вас не устраивают. На первый взгляд они могут казаться очень простыми алгоритмами, но их кажущаяся простота проистекает из их обобщенности, и в девяти случаях из десяти их можно расширить так, что они подойдут для новых задач. Иногда следует стремиться к повторному использованию стандартных алгоритмов, так как это дает гарантию переносимости и эффективности.
Рецепт 7.5.
7.11. Печать диапазона в поток
Имеется диапазон элементов, который требуется напечатать в поток, например, в cout
Напишите шаблон функции, который принимает диапазон или контейнер, перебирает все его элементы и использует алгоритм сору
ostream_iterator
для записи. Если требуется дополнительное форматирование, напишите свой простой алгоритм, который перебирает диапазон и печатает каждый элемент в поток. (См. пример 7.11)#include
#include
#include
#include
#include
using namespace std;
int main() {
// Итератор ввода - это противоположность итератору вывода: он
// читает элементы из потока так. как будто это контейнер.
cout << "Введите несколько строк: ";
istream_iterator
istream_iterator
vector
// Используем выходной поток как контейнер, используя
// output_iterator. Он создает итератор вывода, для которого запись
// в каждый элемент эквивалентна записи в поток.
copy(v.begin(), v.end(), ostreamIterator
}
Вывод примера 7.11 может выглядеть так.
Введите несколько строк: z x y a b с
^Z
z, x, y, a, b, с,
Потоковый итератор — это итератор, который основан на потоке, а не на диапазоне элементов контейнера, и позволяет рассматривать поток как итератор ввода (читать из разыменованного значения и увеличивать итератор) или итератор вывода (аналогично итератору ввода, но для записи в разыменованное значение вместо чтения из него). Это облегчает чтение значений (особенно строк) из потока, что делается в нескольких других примерах этой главы, и запись значений в поток, что делается в примере 7.11. Я знаю, что этот рецепт посвящен записи диапазона в поток, но позвольте мне немного отойти от этой задачи и, поскольку я использую потоковые итераторы во многих примерах этой главы, объяснить, что это такое.
В примере 7.11 показаны три ключевые части istream_iterator
istream_iterator
, указывающего на начало потокового ввода. Это делается вот так.istream_iterator
В результате создается итератор с именем start
vec.begin
(vec
— это vector
) возвращает итератор, который указывает на первый элемент в векторе. Аргумент шаблона string
говорит istream_iterator
, что элементы в этой последовательности имеют тип string
. Аргумент конструктора cin
— это входной поток, из которого производится чтение. Однако это абстракция, так как первого элемента не существует, поскольку из cin
еще ничего прочитано не было. Это произойдет несколько позже.Вторая часть итератора входного потока — это маркер конца, который создается вот так.
istream_iterator