fmtlib/fmt — современный способ форматирования строк в C++ без головной боли
Помните эти многочасовые поиски багов, связанных с printf или нечитаемые цепочки операторов << в iostreams? В современном C++ есть решение элегантнее — библиотека {fmt}, которая уже стала де-факто стандартом для форматирования строк.
Почему все говорят о {fmt}?
Библиотека {fmt} начиналась как альтернатива классическим подходам к форматированию в C++, и за 10 лет превратилась в must-have инструмент. Вот что делает её особенной:
- Скорость: до 20% быстрее
printfи в 20-30 раз быстрееstd::ostringstream - Безопасность: ошибки формата ловятся на этапе компиляции
- Удобство: синтаксис как в Python, но для C++
Неудивительно, что её используют в MongoDB, PyTorch, Windows Terminal и сотнях других проектов.
5 причин попробовать {fmt} прямо сейчас
1. Синтаксис, который полюбят ваши пальцы
Сравните классику:
// Старый добрый printf
printf("User %s (%d years old) logged in", name.c_str(), age);
// Чехарда с iostreams
std::cout << "User " << name << " (" << age << " years old) logged in";
И современный подход:
fmt::print("User {} ({} years old) logged in", name, age);
Кстати, позиционные аргументы ({0}, {1}) поддерживаются из коробки — это мечта для локализации.
2. Безопасность типов на уровне компиляции
Попробуйте сделать так с printf:
std::string s = fmt::format("{:d}", "это не число");
С C++20 вы получите ошибку компиляции, а не падение в runtime. Библиотека проверяет соответствие спецификаторов формата и типов аргументов.
3. Поддержка пользовательских типов
Хотите красиво выводить свои структуры? Легко:
struct Point { double x, y; };
template <>
struct fmt::formatter<Point> {
auto format(Point p, format_context& ctx) {
return format_to(ctx.out(), "({:.1f}, {:.1f})", p.x, p.y);
}
};
Point p{1.5, 2.5};
fmt::print("Точка: {}", p); // Выведет: Точка: (1.5, 2.5)
4. Работа с контейнерами и временем
Библиотека умеет больше, чем просто строки:
// Вектор
std::vector<int> v = {1, 2, 3};
fmt::print("{}", v); // [1, 2, 3]
// Время
auto now = std::chrono::system_clock::now();
fmt::print("Сегодня: {:%Y-%m-%d}", now);
5. Цветной вывод в консоль
Хотите оживить терминальный вывод?
fmt::print(fg(fmt::color::crimson) | fmt::emphasis::bold,
"Hello, {}!", "world");
Что под капотом?
Технически {fmt} — это:
- Header-only библиотека (но можно и линковать отдельно)
- Всего 3 основных файла:
format.h,format-inl.h,base.h - Алгоритм Dragonbox для идеального округления чисел с плавающей точкой
- Поддержка Unicode
- Минимальные накладные расходы (размер кода сравним с
printf)
Кому особенно пригодится?
- Разработчикам кросс-платформенных приложений — одинаковое поведение на всех ОС
- Авторам логгеров — скоростное форматирование критично
- Командам, заботящимся о безопасности — защита от уязвимостей форматных строк
- Всем, кто устал от iostreams — читаемый и лаконичный код
Как начать использовать?
Добавьте в проект через:
# CMake
find_package(fmt REQUIRED)
target_link_libraries(your_target PRIVATE fmt::fmt)
Или просто скопируйте заголовочные файлы, если нужен header-only вариант.
{fmt} — это тот редкий случай, когда библиотека делает код:
- Быстрее ✔️
- Безопаснее ✔️
- Читабельнее ✔️
При этом она уже стала частью стандарта C++20 (std::format), так что изучать её — это инвестиция в будущее. Для старых стандартов — идеальная полифилла.
Советую попробовать на следующем проекте. Как показывает практика, назад к printf или iostreams уже не хочется.
