4. Далее создадим экземпляр типа std::deque
и просто скопируем туда все целые числа из стандартного потока ввода. Двусторонняя очередь сама по себе не является итератором, поэтому обернем ее в std::back_insert_iterator
с помощью вспомогательной функции std::back_inserter
. Эта особая оболочка для итератора позволит выполнить метод v.push_back(item)
для каждого из элементов, получаемых из стандартного ввода. Таким образом, двусторонняя очередь будет расти автоматически!
deque
copy(it_cin, end_cin, back_inserter(v));
5. Воспользуемся std::istringstream
, чтобы скопировать элементы в stream
:
istringstream sstr {"123 456 789"};
6. Далее понадобится подсказка, которая поможет определить, куда именно нужно вставить элемент. Нам нужна середина, поэтому применим начальный указатель, передав его в функцию std::next
. Второй аргумент данной функции говорит о том, что вернет итератор, смещенный на позицию v.size()/2
шагов, т.е. на половину очереди. (Мы преобразуем v.size()
к типу int
, поскольку второй параметр функции std::next
представляет собой difference_type
итератора, использованного в качестве первого параметра. В данном случае это целочисленный тип со знаком. В зависимости от установленных флажков компилятор может предупредить вас, если преобразование не было выполнено явно.)
auto deque_middle (next(begin(v),
static_cast
7. Теперь можно скопировать проанализированные целые числа шаг за шагом из потока ввода строк в очередь. Опять же конечный итератор оболочки итератора потока представляет собой пустой объект типа std::istream_iterator
без аргументов конструктора (поэтому вы можете видеть пустые скобки {}
в строке кода). Очередь оборачивается в итератор вставки, который представляет собой std::insert_iterator
, указывающий на середину очереди с помощью итератора deque_middle
:
copy(istream_iterator
8. Воспользуемся итератором std::front_insert_iterator
, чтобы вставить элементы в начало очереди:
initializer_list
copy(begin(il2), end(il2), front_inserter(v));
9. На последнем шаге выведем содержимое очереди на консоль. Здесь итератор std::ostream_iterator
работает как итератор вывода, что в нашем случае просто перенаправляет все скопированные целые числа в std::cout
, прикрепляя символ ",
" после каждого элемента:
copy(begin(v), end(v), ostream_iterator
cout << '\n';
}
10. Компиляция и запуск программы дадут следующий результат. Можете ли вы определить, какие строки кода добавили каждое число?
$ echo "1 2 3 4 5" | ./main
-3, -2, -1, 1, 2, 123, 456, 789, 3, 4, 5,
Как это работает
Мы использовали множество разных адаптеров. Они имеют только одну схожую черту — оборачивают объект, не являющийся итератором сам по себе, в итератор.
std::back_insert_iterator
В адаптер back_insert_iterator
можно обернуть типы std::vector
, std::deque
, std::list
и т.д. Он будет вызывать метод контейнера push_back
, который вставит новый элемент
std::front_insert_iterator
Адаптер front_insert_iterator
делает то же самое, что и адаптер back_insert_iterator
, но вызывает метод контейнера push_front
, который вставляет новый элемент std::vector
это значит, что все существующие элементы нужно сдвинуть на одну позицию вправо для освобождения места под новый элемент.
std::insert_iterator
Этот адаптер итератора аналогичен другим итераторам вставки, но может вставлять новые элементы std::inserter
, которая создает подобную оболочку, принимает два аргумента. Первый — контейнер, а второй — итератор, указывающий на позицию, в которую будут вставлены новые элементы.
std::istream_iterator