Страницы

Поиск по вопросам

понедельник, 2 декабря 2019 г.

Почему оператор << для ostream не перегружен для контейнеров?

#cpp #cpp11


Почему оператор << для ostream не перегружен для контейнеров, таких как vector, set, map?

И если есть проблемы с перегрузкой оператора << для ostream, то почему бы не добавить
функцию print или print_container, которая бы могла выводить контейнеры.

Спрашиваю больше из-за любопытства и из-за того, что такую мелочь приходится реализовывать
самому. Притом, что во многих других языках выводить контейнеры не составляет труда.
    


Ответы

Ответ 1



Скажите, как правильно выводить vector - через запятую? с фиксированной шириной поля? Может, все брать в скобки? А vector - строки нужно брать в кавычки? или нет? А list - с какой именно точностью и в каком формате выводить? Заметим, это вы решаете не для себя, а для всех программистов на C++... Вы готовы к таким holy wars? А написать свой вывод - секундное же дело. Ну, в крайнем случае напишите copy(c.begin(),c.end(),ostream_iterator(cout,",")) :-) "По-моему, так" (с) Пух

Ответ 2



Во-первых, контейнеры состоят из многих элементов, поэтому не ясно, в каком формате выводить элементы контейнера. Например, можно выводить каждый элемент на новой строке. Можно выводить все элементы на одной строке через пробел. А можно выводить все элементы на одной строке через запятую или точку с запятой и т.д. Во-вторых, контейнеры могут содержать не только фундаментальные типы, но и созданные пользователем типы. В этом случае вообще невозможно заранее предугадать, как должен выглядеть вывод элементов контейнера. Поэтому на самом деле все сводится к перегрузке оператора для вывода самих элементов контейнера. Ответственность за перегрузку оператора для созданных пользователем типов лежит на пользователе. Имея такой перегруженный оператор, не составляет труда вывести все элементы контейнера. Причем таких смособов существует несколько: вы можете использовать стандартные алгоритмы, как, например, std::copy, std::copy_if и другие. Либо можете использовать обычные циклы: for, while, do-while. Либо использовать цикл на основе диапазона. Причем вы можете также задавать условия, по которым будут отбираться элементы для вывода из контейнера. Что касается других языков, то обычно этот вопрос решается за счет того, что все объекты наследуются от одного базового объекта, который имеет виртуальную (или не виртуальную) функцию toString (или ToString). То есть любой объект, который создается пользователем, уже имеет по умолчанию функцию вывода в поток. Или же создаваемые новые объекты уже имеют некоторый минимальный интерфейс, куда входит и функция преобразования объекта к строке. В C++ нет единого объекта, от которого произошли все другие объекты, а потому нет заранее предопределенной функции преобразования произвольного объекта к строке, которую можно вывести в поток.

Ответ 3



Технически проблем никаких нет. Для разделителей, скобок и прочих украшений ничего не мешает добавить такие же модификаторы как для интегральных типов. Релизация могла бы выглядеть так: template std::ostream & operator << ( std::ostream & printer , const std::vector & items ) { printer << std::begin_scope(); std::copy( items.begin() , items.end () , std::ostream_iterator( printer , std::delimeter()) ); printer << std::end_scope(); return printer; } В части ввода/вывода, воспроизвели функционал стандартной библиотеки Си только на Си++ :) Предпологается что программист сам как ему надо руками напишет.

Ответ 4



Думаю, проблема реализации вывода в поток у стандартных контейнеров гораздо более серьезная, чем выбор формата вывода и сепораторов. Допустим оператор << у контейнеров STL реализован. Разумеется, самое простое, что можно придумать - он обходит все айтемы и помещать их в выходной поток тем же оператором <<. Отсюда резонное требования ко всем типам, используемых в контейнерах - наличие оператора вывода в поток. Согласитесь, не очень гибко

Комментариев нет:

Отправить комментарий