fmtlib/fmt — современный способ форматирования строк в C++ без головной боли

20 сен 2025
25,873
3,081
326
4 дня

Помните эти многочасовые поиски багов, связанных с 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)

Кому особенно пригодится?

  1. Разработчикам кросс-платформенных приложений — одинаковое поведение на всех ОС
  2. Авторам логгеров — скоростное форматирование критично
  3. Командам, заботящимся о безопасности — защита от уязвимостей форматных строк
  4. Всем, кто устал от iostreams — читаемый и лаконичный код

Как начать использовать?

Добавьте в проект через:

# CMake
find_package(fmt REQUIRED)
target_link_libraries(your_target PRIVATE fmt::fmt)

Или просто скопируйте заголовочные файлы, если нужен header-only вариант.

{fmt} — это тот редкий случай, когда библиотека делает код:

  • Быстрее ✔️
  • Безопаснее ✔️
  • Читабельнее ✔️

При этом она уже стала частью стандарта C++20 (std::format), так что изучать её — это инвестиция в будущее. Для старых стандартов — идеальная полифилла.

Советую попробовать на следующем проекте. Как показывает практика, назад к printf или iostreams уже не хочется.

🍪 Мы используем файлы cookie и сервис аналитики Яндекс.Метрика, чтобы сайт работал лучше. Продолжая пользоваться devtrends.ru, вы соглашаетесь с обработкой данных согласно Политике конфиденциальности.