LINUX.ORG.RU

C++ fmt

 


0

1

Часто вижу упоминание fmt как хорошего решения. По мне это хуже читается чем "id = " + hex{id} + " date = " + yyyymmdd{date} + '\n' или с потоками через <<. Хуже как минимум необходимостью сопоставлять скобки и аргументы. Вроде там есть режим с именованием, но в схеме выше даже имена не нужны - и так видно, что где будет. Чем оно хорошо на ваш взгляд и почему настолько популярно?

Не надо конвертировать значения в строку для соединения и хранить эту строку, сразу виден шаблон в который будут заполняться значения, различные спецификаторы которые определяют как именно будет отформатированно число.

MOPKOBKA ★★★★★
()

Крестовики и сишники любят ещё упарываться в производительность. Так что если им дать способ вывода который будет максимально уродлив и неудобен, но быстр, то они все на него перекатятся.

peregrine ★★★★★
()

или с потоками через <<

#include <iomanip>
#include <iostream>
#include <string_view>
 
int main()
{
    constexpr std::string_view s{"abc"};
    constexpr int width{5};
 
    // fill/left/right properties are kept until changed
    std::cout << std::setfill('-');
    std::cout << std::left;
 
    std::cout << '[' << std::setw(width) << s << "]\n";
    std::cout << '[' << std::setw(width) << s << "]\n";
 
    std::cout << std::right;
    std::cout << '[' << std::setw(width) << s << "]\n";
 
    // width is reset after each call
    std::cout << '[' << s << "]\n";
}

Ну прелесть же!

dataman ★★★★★
()
Ответ на: комментарий от thunar

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

peregrine ★★★★★
()
Последнее исправление: peregrine (всего исправлений: 1)
Ответ на: комментарий от MOPKOBKA

Так нигде же не надо конвертировать. Вопрос больше по синтаксису, если что(+ и << просто для примера, то что для string нету op+(string, auto) здесь неважно).

сразу виден шаблон в который будут заполняться значения

Есть такое, зато аргументы видны не сразу. Ну допустим как один из плюсов.

различные спецификаторы которые определяют как именно будет отформатированно число

Специально добавил пару вариантов с простым форматированием в оп.

qweururu
() автор топика
Ответ на: комментарий от qweururu

Так нигде же не надо конвертировать

Ну число в строку же надо. Если нужен не %f а %g.

Специально добавил пару вариантов с простым форматированием в оп.

Длинно получается, и будет не так, а вот так: std::garbage::hex{}.

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 1)
Ответ на: комментарий от dataman

Ну так это не у C++ проблема, а у программистов. Я вон видел как-то sql (чел руками писал, не генератором кода каким-то, даже чат гопоты ещё не было и у чела навыка написать код который пишет код не было) запрос который в одну строчку был и длинной ну даже сложно сказать какой (тысячи слов и вложенные циклы с ветвлением).

peregrine ★★★★★
()
Ответ на: комментарий от dataman

Ну прелесть же!

Конечно прелесть, оно же древнее C++98, если не ошибаюсь. Что мешало написать как-то так:

auto ls = left_align{s, 5, '-'};
cout << '[' << ls << "]\n"
     << '[' << ls << "]\n"
     << '[' << right_align{s, 5, '-'} << "]\n"
     << '[' << s << "]\n";

Речь не про уже существующие решения, напомню. Ну и аналог на fmt ты не показал.

qweururu
() автор топика
Ответ на: комментарий от MOPKOBKA

Ну число в строку же надо. Если нужен не %f а %g.

Да нет, почему. Те же спецификаторы, но представленные по-другому. Я не понимаю проблемы.

Длинно получается, и будет не так, а вот так: std::garbage::hex{}.

Ну garbage-то не будет. А вообще, с «.02» и подобным конечно трудно соревноваться в краткости, но оно менее понятное, разве нет? Как раз из-за краткости.

qweururu
() автор топика
Ответ на: комментарий от peregrine

Здесь нет никакой разницы в производительности, разница только в синтаксисе. Я забыл в оп написать и наверное непонятно получилось, но вопрос только про синтаксис. Сравнивать что-то новое с потоками 30-ти летней давности тянущими совместимость не нужно.

qweururu
() автор топика
Ответ на: комментарий от dataman
cout << '[' << left_align{s, 5, '-'} << "]\n"
     << '[' << right_align{s, 5, '-'} << "]\n"

vs

println("[{:-<5}]", s);
println("[{:->5}]", s);

Ну вот, та же прелесть, только другого плана, нет?

Вообще для fmt-подобного другая прелесть тоже возможна, ровно тем же способом, как и для потоков, например. Как и для потоков что-то такое s << "[{:->5}]\n"f(s). Видимо выше единственный аргумент за fmt сообщили(хорошо видно паттерн). Неясно только, почему большинство предпочитает видеть паттерн, а не аргументы.

qweururu
() автор топика
Ответ на: комментарий от peregrine

будет максимально уродлив и неудобен, но быстр, то они все на него перекатятся.

Автору https://github.com/robhz786/strf вот так нравится:

    using namespace strf::format_functions;

    assert(strf::to_string(dec(123) > 8)  == "     123");
    assert(strf::to_string(dec(123) < 8)  == "123     ");
    assert(strf::to_string(dec(123) ^ 8)  == "  123   ");

    assert(strf::to_string(right(123, 8))        == "     123");
    assert(strf::to_string(right(123, 8,  '~'))  == "~~~~~123");
    assert(strf::to_string(left(123, 8,  '~'))   == "123~~~~~");
    assert(strf::to_string(center(123, 8,  '~')) == "~~123~~~");
dataman ★★★★★
()
Ответ на: комментарий от qweururu

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

unC0Rr ★★★★★
()
Ответ на: комментарий от dataman

right(123, 8, ‘~’)

Ну вот, кстати, что-то подобное. Даже краткий вариант есть(dec(123) > 8). Мне нравится, надо будет подробнее посмотреть. Непонятно только зачем явный to_string в сравнении понадобился, но то ладно.

qweururu
() автор топика
Ответ на: комментарий от qweururu

Мне нравится, надо будет подробнее посмотреть.

Ну, в strf есть интересные фичи, например: https://robhz786.github.io/strf/v0.16.2/quick_reference.html#tr_string

The tr-string is like what in other formatting libraries would be called as the format string, except that it does not specify any formatting. Its purpose is to enable your program to provide multilingual support by using translation tools like gettext.

Это к вопросу о локализации.

dataman ★★★★★
()

Через fmt, удобнее делать логирование, локализацию и т.д. Она визуально занимает намного меньше места, чем + и <<, единообразный и человеческий подход к форматированию свяких дат и чисел, отсюда понятность её выше, особенно, если нужно сформировать большие строки, и если делать как-нить так

fmt::print("Name: {name}, Age: {age}\n", fmt::arg("name", "Bob"), fmt::arg("age", 25))

возможность выводить цвета и всякое разное в консоль ну и куча всего остального делают сей инструмент популярным.

vtVitus ★★★★★
()
Последнее исправление: vtVitus (всего исправлений: 1)
Ответ на: комментарий от qweururu

... но оно менее понятное, разве нет? Как раз из-за краткости.

Если это все заученно, то как раз более понятнее, потому что можно быстро прочесть и понять. Деление, сложение, умножение - все это записывается какой то странной одиночной закорючкой да еще и с какими то приоритетами, но A+2*B/C понятнее чем add(A, div(mul(2, B), C)) и уж тем более быстрее читается чем std::add{A, std::div{std::mul{2, B}, C}}

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 2)
Ответ на: комментарий от dataman

Это к вопросу о локализации.

Мне пытались сказать о том, что это(tr("id = {} date = {}")) сработает только на чём-то одинаковом(на паттерне), но работать перестанет, как только строка поменяется при подстановке аргументов? Ну в какой-то степени проблема имеется, потому что без паттерна придётся tr() писать чаще.

qweururu
() автор топика
Ответ на: комментарий от qweururu

Где то имя надо писать перед Hello, где то после, в программе была строка:

printf(ID_HELLO, name);
Файл переводов такой:
ru:ID_HELLO = "Привет, {0}\n"
xx:ID_HELLO = "{0}, Hello\n"
Или более сложный пример:
printf(ID_HELLO, first_name, last_name);
ru:ID_HELLO = "Привет, {0} {1}\n"
xx:ID_HELLO = "{1} {0}, Hello\n"

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 3)
Ответ на: комментарий от qweururu

Непонятно только зачем явный to_string в сравнении понадобился

Потому что возвращается тип, не имеющий оператора сравнения с const char *, очевидно же.

LamerOk ★★★★★
()
Ответ на: комментарий от MOPKOBKA

add(A, div(mul(2, B), C))

У тебя пример некорректный, должно быть A add 2 mul B div C(или + A / * 2 B C). А так согласен.

Там выше было это s << '[' << "->5"f(s) << "]\n" и это dec(123) > 8. Коротко можно в любом из вариантов.

qweururu
() автор топика
Ответ на: комментарий от peregrine

Так что если им дать способ вывода который будет максимально уродлив и неудобен, но быстр, то они все на него перекатятся.

Так можно выбрать что-то одно, либо красоту, либо скорость. Тк эти языки ничего не знают о красоте, то выбор очевиден.

Obezyan
()

Разве что его способность работать в компилтайме. Но я сильно сомневаюсь, что это активно применять будут, как и компиляцию форматов.
Я уже делал printf, который по производительности не уступает fmt:
https://gitlab.com/mittorn/xrBinder/-/blob/master/src/fmt_util.h?ref_type=heads
При этом сам же его не использую т.к он заметно негативно влияет на время компиляции.
fmt впрочем тоже негативно сказывается на времени компиляции (как и любой сложный алгоритм, умеющий в constexpr т.к оптимизатор пытается весь его развернуть)
Но у fmt есть ещё такая особенность: у него совершенно нечитаемые исходники. Это просто обфусцировуанная каша из шаблонов и самый простой способ понять, как он работает - скомпилировать код и декомпилирвать обратно - внезано, нечитаемая каша превращается в какой-то алгоритм...

mittorn ★★★★★
()
Ответ на: комментарий от vtVitus
fmt::print("Name: {name}, Age: {age}\n", fmt::arg("name", "Bob"), fmt::arg("age", 25))

Вот это вот позволяет нормально выполнять локализацию программ.

А уже сделали что-то уровня QLinguist для работы с этим переводчиками?

blex ★★★★
()

Чем оно хорошо на ваш взгляд и почему настолько популярно?

Печать в stdout это последнее что может прийти в голову в реальной программе. А печать в stdout в помощью iostream из C++ — тем более.

В реальных программах используют логгеры, например Boost.Log.

zx_gamer ★★★
()
Ответ на: комментарий от zx_gamer

Печать в stdout это последнее что может прийти в голову в реальной программе. А печать в stdout в помощью iostream из C++ — тем более.

В Вашем мире консольных программ не существует, осталась только Chrome OS?

Попробуйте написать grep или ping без вывода в stdout.

monk ★★★★★
()
Ответ на: комментарий от zx_gamer

И то, и другое написано на Си. И это программы без интерфейса, программы с интерфейсом используют ncurses, как правило.

Есть fgrep на Си++. Или клиент к MariaDB.

это программы без интерфейса

Интерфейс командной строки для Вас уже не интерфейс?

программы с интерфейсом используют ncurses, как правило

То программы с очень ограниченным списком действий используют ncurses. Я не представляю себе в виде ncurses полный список параметров grep или find.

monk ★★★★★
()