Skip to main content

A Practical Guide to Using the {fmt} Library in Modern C++

·549 words·3 mins
C++ Fmt Formatting Modern-Cpp
Table of Contents

๐Ÿงฉ What Is the {fmt} Library?
#

The {fmt} library is a modern, high-performance formatting library for C++. It provides a safe, fast, and expressive alternative to both Cโ€™s printf family and C++โ€™s iostreams.

It combines:

  • The type safety of C++ streams
  • The performance of printf
  • A clean, readable syntax inspired by Python and Rust

Most importantly, {fmt} is the foundation of std::format, which was standardized in C++20.


โš™๏ธ Installation and Basic Setup
#

The library can be used either as a compiled dependency or as header-only, which is ideal for small tools and utilities.

Header-Only Setup
#

#define FMT_HEADER_ONLY
#include "fmt/core.h"

int main() {
    fmt::print("Hello, {fmt}!\n");
}

This approach:

  • Requires no linker configuration
  • Works well for embedded tools and utilities
  • Is convenient for quick prototyping

๐Ÿงช Core Syntax: {} Placeholders
#

Unlike printf, which relies on cryptic % specifiers, {fmt} uses curly braces {} as placeholders.

Simple Output
#

fmt::print("Answer = {}\n", 42);

Output:

Answer = 42

Formatting into a String
#

std::string msg = fmt::format("Voltage = {} V", 3.3);

This is ideal for:

  • Logging systems
  • Error messages
  • Network payload construction

๐Ÿ”ข Argument Handling and Ordering
#

Each {} corresponds to an argument passed to the formatting function.

Sequential Arguments (Default)
#

fmt::println("{} + {} = {}", 2, 3, 5);

Positional Arguments
#

fmt::println("{1} then {0}", "first", "second");

Output:

second then first

Named Arguments
#

Named arguments greatly improve readability for complex formats.

fmt::print(
    "User: {name}, Score: {score}\n",
    fmt::arg("name", "Alice"),
    fmt::arg("score", 95)
);

๐ŸŽ›๏ธ Format Specifiers in Detail
#

Format specifiers appear after a colon : inside the braces.

fmt::print("{:format_spec}", value);

Width, Alignment, and Padding
#

fmt::println("|{:>10}|", "right");
fmt::println("|{:^10}|", "center");
fmt::println("|{:<10}|", "left");
fmt::println("|{:*^10}|", "fmt");

Output:

|***fmt****|

Floating-Point Precision
#

fmt::println("{:.2f}", 3.1415926);
fmt::println("{:.4f}", 3.1415926);

Integer Bases
#

fmt::println("Dec: {}", 42);
fmt::println("Hex: {:x}", 42);
fmt::println("Bin: {:b}", 42);

๐Ÿงฑ Formatting Custom Types
#

One of {fmt}โ€™s most powerful features is custom formatters.

Example: Formatting a Struct
#

struct Point {
    int x;
    int y;
};

template <>
struct fmt::formatter<Point> {
    constexpr auto parse(format_parse_context& ctx) {
        return ctx.begin();
    }

    template <typename FormatContext>
    auto format(const Point& p, FormatContext& ctx) {
        return fmt::format_to(ctx.out(), "({}, {})", p.x, p.y);
    }
};

Usage:

Point p{3, 4};
fmt::println("Point = {}", p);

This makes {fmt} ideal for:

  • Debug output
  • Logging complex data structures
  • Diagnostics in large systems

๐Ÿš€ Performance and Safety Advantages
#

Why {fmt} Beats printf
#

  • Compile-time format string checking
  • No undefined behavior from mismatched arguments
  • Easier refactoring

Why {fmt} Beats std::cout
#

  • No heavy stream state
  • Fewer temporary objects
  • Significantly faster in hot paths

This makes {fmt} particularly attractive for:

  • High-frequency logging
  • Networking and protocol stacks
  • Performance-sensitive tools

๐Ÿ” Relationship with std::format
#

Feature {fmt} std::format
Maturity Very mature Newer
Performance Often faster Slightly slower
Customization Extensive Limited
Standardized No Yes (C++20)

Many projects still prefer {fmt} even on C++20+ compilers due to its richer feature set and battle-tested stability.


๐Ÿ“Š Comparison Summary
#

Feature {fmt} printf std::cout
Type Safety โœ… โŒ โœ…
Readability High Low Medium
Performance High Medium Low
Extensibility Excellent None Limited
Modern C++ โœ… โŒ โš ๏ธ

โœ… Final Thoughts
#

If you are writing modern C++, {fmt} should be your default formatting choice:

  • Cleaner than cout
  • Safer than printf
  • Faster than both
  • Future-proof thanks to C++20 adoption

Once you adopt {fmt}, going back to stream operators feels like stepping into the past.

Related

Top 10 Coding Habits Every Professional Programmer Should Master
·602 words·3 mins
Programming Best-Practices C++ Software-Engineering
Modern C++ Trailing Return Types Explained
·459 words·3 mins
Cpp Modern-Cpp Templates Language-Features
Mastering WSL with Ubuntu 24.04: Fast, Portable Dev Environments
·535 words·3 mins
Ubuntu WSL Windows Linux Development