Очень легко вывести что-то на экран с помощью потоков вывода, поскольку в STL есть много полезных перегруженных версий оператора <<
std::ostream_iterator
, что мы довольно часто делали.В данном примере мы сконцентрируемся на том, как это сделать для пользовательского типа и что еще можно сделать для управления выводом на экран с помощью выбора типа шаблона без необходимости писать при этом много кода на вызывающей стороне.
Как это делается
В этом примере мы поработаем с итератором std::ostream_iterator
1. Сначала указываем, какие заголовочные файлы включить, а затем объявляем об использовании пространства имен std
#include
#include
#include
#include
#include
using namespace std;
2. Реализуем функцию преобразования, которая соотносит числа и строки. Она будет возвращать строку "one"
1
, "two"
для значения 2
и т.д.:string word_num(int i) {
3. Мы заполним ассоциативный массив, основанный на хешах, этими парами, чтобы получить к ним доступ позже:
unordered_map
{1, "one"}, {2, "two"}, {3, "three"},
{4, "four"}, {5, "five"}, //...
};
4. Теперь можно передать в функцию find
i
и вернуть то значение, которое она найдет. Если функция ничего не найдет — например, для заданного числа нет перевода, — то вернем строку "unknown"
: const auto match (m.find(i));
if (match == end(m)) { return "unknown"; }
return match->second;
};
5. Мы будем работать также со структурой bork
print
, которая принимает ссылку на поток вывода и выводит строку "bork"
столько раз, сколько указано в целочисленной переменной borks
:struct bork {
int borks;
bork(int i) : borks{i} {}
void print(ostream& os) const {
fill_n(ostream_iterator
borks, "bork!"s);
}
};
6. Для использования функции bork::print
<<
для объектов потока, чтобы они автоматически вызывали функцию bork::print
, когда объекты типа bork
попадают в поток вывода:ostream& operator<<(ostream &os, const bork &b) {
b.print(os);
return os;
}
7. Теперь наконец можем начать реализовывать саму функцию main
int main()
{
const vector
8. Для объектов типа ostream_iterator
ostream_iterator
, то в дальнейшем для вывода данных на экран будет применяться конструкция ostream& operator(ostream&, const T&)
. Именно это свойство мы и реализовали до типа bork
. На сей раз просто выводим целые числа, поэтому специализация выглядит как ostream_iterator
. Для вывода информации на экран мы будем использовать поток cout
, так что предоставим его в качестве параметра конструктора. Пройдем по вектору в цикле и присвоим каждый элемент i
разыменованному итератору вывода. Именно так потоковые итераторы используются в алгоритмах STL. ostream_iterator
for (int i : v) { *oit = i; }
cout << '\n';
9. Полученный от итератора результат нам подходит, но он выводит числа без каких-либо разделителей. Если мы хотим добавить пробелы-разделители между всеми выведенными элементами, то можем предоставить собственную строку с пробелами в качестве второго параметра конструктора итератора выводного потока. Данное действие позволит вывести строку "1, 2, 3, 4, 5, "
"12345"
. К сожалению, мы не можем указать отбросить пробел с запятой после последнего числа, поскольку итератор не знает, что достиг конца строки, до тех пор, пока это не случится. ostream_iterator
for (int i : v) { *oit_comma = i; }
cout << '\n';