Здравствуйте, so5team, Вы писали:
S>А если добавить, что для printable потребуется не один виртуальный метод, а два (первый нужен для хранения результатов разбора форматной строки)
Не понял. Предполагается, что метод print просто печатает текущий объект в output_stream посимвольно.
Более простой вариант — сделать вместо этого метод to_string(). Но тут придётся между печатью хранить строку. В большинстве языков делают именно так, хотя мне это кажется не оптимальным и даже менее удобным для реализации.
Т.е. используется это так: printf("%s", my_obj). И printf уже вызовет у my_obj метод print, которым он напечатает себя в stdout.
Использовать что-либо кроме %s для печати своих объектов мне кажется странной идеей, но можно и это сделать, просто в метод print передавать вторым парамметром запрошенный модификатор форматирования. Наверное это может иметь смысл для своих числовых типов.
Здравствуйте, vsb, Вы писали:
vsb>Т.е. используется это так: printf("%s", my_obj). И printf уже вызовет у my_obj метод print, которым он напечатает себя в stdout.
Посмотрите как поддержка пользовательских типов сделана в fmtlib: https://fmt.dev/10.0.0/api.html#formatting-user-defined-types
Там требуется два метода: parse (в принципе, он опциональный, если нет собственных требований к форматной строке) и format.
vsb>Использовать что-либо кроме %s для печати своих объектов мне кажется странной идеей, но можно и это сделать, просто в метод print передавать вторым парамметром запрошенный модификатор форматирования.
Два разных метода позволяют разделить парсинг форматной строки и собственно формат. Тем самым, если парсинг осуществляется в compile-time, то и всякие ошибки с форматом выявляются именно там.
Выделенное жирным является сутью этой дискуссии: кому-то кажется одно, но с большой долей вероятности этот кто-то даже не представляет, что кажется и что нужно другим людям.
Здравствуйте, CRT, Вы писали:
S>>Смотря где. В VC++ нормальная поддержка шаблонов из C++98 появилась только в VS2003.
CRT>Тоже давным давно уже
При этом operator<< как были введены в C++ начала 1980-х, так и работали.
CRT>>>а этот format() когда появился?
S>>После принятия C++11, т.к. ему вариадики нужны были.
CRT>а cppreference.com пишет C++20
CRT>в стандарте его не было
Речь не про std::format, а про fmtlib из которой std::format и появился. Эта самая fmtlib стала возможной только после принятия C++11.
CRT>>а cppreference.com пишет C++20
CRT>>в стандарте его не было
S>Речь не про std::format, а про fmtlib из которой std::format и появился. Эта самая fmtlib стала возможной только после принятия C++11.
Так я о чем и говорю что в стандарт они его добавили недавно. То есть частью языка (если считать стандартные библиотеки частью языка), он стал совсем недавно
Здравствуйте, so5team, Вы писали:
S>Выделенное жирным является сутью этой дискуссии: кому-то кажется одно, но с большой долей вероятности этот кто-то даже не представляет, что кажется и что нужно другим людям.
На самом деле у меня своего мнения не так уж много. Мне пришлось поработать с разными языками, и поэтому я своё мнение лишь складываю исходя из сравнения того, как похожие вещи сделаны в разных языках.
Поэтому когда я говорю, что мне кажется, что использовать что-то кроме %s для пользовательских типов не нужно, в основном это вызвано тем, что я не знаю ни одного языка, где это было бы. В Java есть String.format, в нём %s вызывает toString() у пользовательского объекта. В Objective C есть %@, там тоже какой-то подобный метод. В Go то же самое. И если вдруг понадобится какой-то нестандартный метод для форматирования, достаточно просто написать метод to_custom_string(), возвращающий строку или же написать объект-обёртку, если этот объект такой гигантский, что промежуточная строка ну никак не подходит.
Допускаю, что на этих языках есть люди, которые страшно страдают от того, что не могут указать свой формат для форматирования прямо в строке. Но мне кажется, что таких людей мало. А людей, которые продуктивно используют простую и понятную систему — много.
Здравствуйте, CRT, Вы писали:
CRT>Так я о чем и говорю что в стандарт они его добавили недавно. То есть частью языка (если считать стандартные библиотеки частью языка), он стал совсем недавно
Э... А как это меняет тот факт, что в 1980-х в C++ смогли сделать только безопасный по типам operator<<?
Здравствуйте, vsb, Вы писали:
vsb>Поэтому когда я говорю, что мне кажется, что использовать что-то кроме %s для пользовательских типов не нужно, в основном это вызвано тем, что я не знаю ни одного языка, где это было бы.
Это логика из категории "если миллионы мух"...
C++ очень сильно отличается от Java или Objective C.
Например, в нем ООП не обязательно.
Следовательно, нет какой-то вершины иерархии, вроде Object, в которую можно было зафигачить toString.
Кроме того, в C++ многие упарываются по производительности и накладным расходам.
И если навязать подход, когда парсинг только в run-time, для вывода нужно вызывать виртуальный toString, а этот toString еще и вернет std::string с динамической аллокацией внутри, то подобное решение очень быстро закидают гнилыми помидорами.
Здравствуйте, so5team, Вы писали:
vsb>>Поэтому когда я говорю, что мне кажется, что использовать что-то кроме %s для пользовательских типов не нужно, в основном это вызвано тем, что я не знаю ни одного языка, где это было бы.
S>Это логика из категории "если миллионы мух"...
Ну как бы и тема про то, почему на других языках писать комфортнее.
S>C++ очень сильно отличается от Java или Objective C. S>Например, в нем ООП не обязательно. S>Следовательно, нет какой-то вершины иерархии, вроде Object, в которую можно было зафигачить toString.
Я уже писал пример, при котором вершина иерархии не нужна. Я вообще не считаю, что Object.toString() было правильным решением. Дефолтная реализация бесполезная, а если уж свою реализацию делать, можно и интерфейс реализовать. Да и печатать удобней в поток, а не в строку.
S>Кроме того, в C++ многие упарываются по производительности и накладным расходам.
Это обычно прямо противоречит "писать проще и комфортнее".
S>И если навязать подход, когда парсинг только в run-time, для вывода нужно вызывать виртуальный toString, а этот toString еще и вернет std::string с динамической аллокацией внутри, то подобное решение очень быстро закидают гнилыми помидорами.
Напоминаю, что изначально я не предлагал возвращать string, поэтому динамическая аллокация тут не обязательна.
А виртуальный вызов? Ну это же ввод-вывод. Это не то, что будет тормозить.
Здравствуйте, vsb, Вы писали:
vsb>>>Поэтому когда я говорю, что мне кажется, что использовать что-то кроме %s для пользовательских типов не нужно, в основном это вызвано тем, что я не знаю ни одного языка, где это было бы.
S>>Это логика из категории "если миллионы мух"...
vsb>Ну как бы и тема про то, почему на других языках писать комфортнее.
Но вы в нее приходите с логикой "а вот в других языках по другому". Ну так на то они и другие языки.
S>>C++ очень сильно отличается от Java или Objective C. S>>Например, в нем ООП не обязательно. S>>Следовательно, нет какой-то вершины иерархии, вроде Object, в которую можно было зафигачить toString.
vsb>Я уже писал пример, при котором вершина иерархии не нужна.
Давайте будем последовательны. Вы привели пример, в котором общий корень не нужен. Его обсудили. Затем вы в дополнение к тому, что уже было обсуждено, добавляете еще:
В Java есть String.format, в нём %s вызывает toString() у пользовательского объекта. В Objective C есть %@, там тоже какой-то подобный метод.
И я отвечаю вам на то, что вы добавили. Пока все вроде логично, не так ли?
Но потом вы опять апеллируете к предыдущему примеру. И тут мне непонятно зачем.
S>>Кроме того, в C++ многие упарываются по производительности и накладным расходам.
vsb>Это обычно прямо противоречит "писать проще и комфортнее".
Ну так прикладные ниши, которые еще остались у C++, они же как раз про производительность, накладные расходы и предсказуемость.
И тем, кто вынужден продолжать пользоваться C++, хочется в этих условиях "писать проще и комфортнее" насколько это возможно.
Отсюда и использование своеобразных практик, на которые в языках, где производительностью, накладными расходами и предсказуемостью, упарываются на так сильно, не идут. Вот те же шаблоны, из-за которых компиляция тормозит, зато в run-time нет лишней косвенности на виртуальных вызовах.
vsb>А виртуальный вызов? Ну это же ввод-вывод. Это не то, что будет тормозить.
Смотря куда будет вывод идти, если в буфер в разделяемой памяти, то вполне может тормозить, особенно если вызывается несколько миллионов раз в секунду.
Здравствуйте, so5team, Вы писали:
vsb>>А виртуальный вызов? Ну это же ввод-вывод. Это не то, что будет тормозить.
S>Смотря куда будет вывод идти, если в буфер в разделяемой памяти, то вполне может тормозить, особенно если вызывается несколько миллионов раз в секунду.
А текущая система iostreams — она как в таком раскладе работает? Много слышал про её тормоза, сам не мерял, правда.
Здравствуйте, vsb, Вы писали:
S>>Смотря куда будет вывод идти, если в буфер в разделяемой памяти, то вполне может тормозить, особенно если вызывается несколько миллионов раз в секунду.
vsb>А текущая система iostreams — она как в таком раскладе работает? Много слышал про её тормоза, сам не мерял, правда.
Да, говорят, что тормозит. Например, на github-е fmtlib есть такие результаты:
Но, помнится по рассказам тех, кто в std::ostream погружался, там куча заморочек с локализацией, что добавляет тормозов.
В принципе, можно свою реализацию ostream-а сделать, где бы лишнего не было. Но это непросто, насколько я помню.
Здравствуйте, so5team, Вы писали:
S>>>дабл выводится там, где требуется строка CC>>А что должно выводиться? S>Должна быть ошибка, ибо если ждали строку, а получили double, то что-то явно пошло не так.
А вот представь что это логгинг в ветке, которая редко выполняется. В итоге мы знаем что что то пошло не так но вообще не знаем ничего больше.
Так что на порядки лучше получить не совсем правильно отформатированные данные чем совсем ничего.
S>Округлять вещественное до целого можно по разному, пользователь должен задавать это явным способом
См выше.
S>Значит должна быть ошибка в run-time.
Вывод сообщения об ошибке вернул ошибку и ничего не вывел — это проблема куда хуже.
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, so5team, Вы писали:
S>Затем, что речь идет о моменте выхода C++ в мир, когда выбор был между сишными функциями и изобретением чего-то другого. Изобрели iostream и перегрузку operator<<. С перегрузкой оператора получилось нормально, практично
Вот как раз практичность и пострадала.
S>(если не обращать внимания на вопли пуристов из разряда "да как они посмели поступить так с оператором битового сдвига"
Оператор точка был бы удобнее, тем что у них вышло таки пользоваться неудобно.
S>Речь про прошлое, в котором в C++ шаблонов не было, не говоря уже про вариадики.
Для printf-like достаточно было оператора запятая.
S>>>Во-вторых, как с помощью мифического crprintf вывести объект собственного типа? CC>>А где в исходнои примере ("std::cout << "0x" << std::hex << std::setfill('0') << std::setw(4) << 0x424 << std::endl;") объект собственного типа? S>Да легко:
Ты не понял вопроса.
CC>>Впрочем если припрёт то всё что надо это определить функцию в namespace которая будет принимать контекст и const& на нужный тип и внутри сама форматировать его в строку. S>Ну вот в fmtlib пошли по этому пути, только там не функцию, а специализацию шаблона нужно определять.
Мне эта либа не понравилась, переусложнили.
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, CRT, Вы писали:
CRT>сишный printf с его языком форматирования гораздо удобней чем cout, но опаснее.
Нынче (да и раньше тоже) легко на С++ делался printf с тем же языком только безопасный.
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, so5team, Вы писали:
S>Можно было, наверное, сделать функцию print(stream, arg), которую можно было бы перегружать для пользовательских типов.
Просто перегрузи оператор запятая для класса форматтера, который вернёт основное тело printf_core(const char* fmt)
Потом через вариадик-макрос делается обёртка, которая строку форматирования передаёт в функцию, которая возвращает объект форматтера а все аргументы __VA_ARGS__ автоматом туда добавит через запятую, ну и заворачивает это всё в скобочки чтоб не вылезло.
Оператор запятая там работает абсолютно так же как и operator<<
Вариадик темплейты это всё делают банально сильно аккуратнее, без необходимости перегрузки именно оператора, тупо функцию форматтер добавляешь для нужного типа.
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, so5team, Вы писали:
CC>>Да вон даже в стандарте std::format наконец предложили. Только он всё равно какой то корявый у них вышел. S>Так в том-то и фокус: однозначно лучше не получилось.
Да потому я и не люблю стандартную библиотеку — они там гонятся за тем, чтоб сделать её максимально generic и получается что то недоубоваримое. Всё такое расширяемое, такое гЫбкое что на ногах не стоит.
S>Как только вы ее выпустите в свет
А зачем? Она написана решать конкретные задачи, и их прекрасно решает. Задачи сделать универсальный всемогутор не стояло и не будет.
На основе этого кода уже написаны несколько версий, заточенных под совсем другое, и они тоже работают максимально хорошо для своих применений. Если же генерализировать чтоб и туда и сюда подходило — получится что то громоздкое и такое же хреновое как и в стандартной.
S>Т.е. эпитеты "отвратительно спроектированный интерфейс"
А лепить цепочку через << это и есть отвратительный интерфейс. Ибо это кошмарно неудобно, особенно на фоне других решений.
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, vsb, Вы писали:
vsb>Впрочем может быть современные компиляторы научились компилировать шаблоны один раз? Плохо представляю, как это может работать, но вроде были какие-то precompiled headers, которые я так и не смог "завести".
ICC давно умеет в автоматические precompiled headers для которых вообще ничего врукопашную делать не надо. Работает замечательно.
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, so5team, Вы писали:
S>C++ пока еще очень сдерживает модель компиляции, унаследованная из C: одни и те же заголовочные файлы приходится парсить помногу раз.
Давно решено на уровне компилятора в нормальных компиляторах. Результаты кэшируются.
S> Повсеместное пришествие поддержки модулей из C++20 должно улучить ситуацию. Ускорить где-то на 1/3
Да уже лет 10 как проблемы на практике нету
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока