{fmt} Formatting & Printing Library {fmt} Formatting & Printing Library {fmt}

    • faster than common implementations of iostreams, (s)printf, to_string and to_chars
    • convenient: format string syntax similar to Python's format
    • type-safe alternative to printf
    • can be used header-only or separately compiled

    This article is based on {fmt} version 8.0.1

    Basic Setup (Install, Compile, …)

    Installation / Download

    $ git clone https://github.com/fmtlib/fmt.git

    Conan

    Header Only Usage

    $ g++ -I fmt/include -o greet hello.cpp
    $ ./greet
    Hello, World!

    A minimum viable setup needs the files core.h, format.h and format-inl.h found in fmt/include/fmt/.

    Using With CMake (Recommended)

    $ cd demo      # project directory
    $ mkdir build  # directory for build output
    $ cd build
    $ cmake ..     # generate build scripts
    $ make Scanning dependencies of target fmt
    [ 20%] Building CXX object fmt/CMakeFiles/fmt.dir/src/format.cc.o
    [ 40%] Building CXX object fmt/CMakeFiles/fmt.dir/src/os.cc.o
    [ 60%] Linking CXX static library libfmt.a
    [ 60%] Built target fmt
    Scanning dependencies of target greet
    [ 80%] Building CXX object CMakeFiles/greet.dir/hello.cpp.o
    [100%] Linking CXX executable greet
    [100%] Built target greet
    $ ./greet
    Hello, World!

    Separate Build & Installation   Build+Install

    see here for more details

    $ cd fmt
    $ mkdir build   # directory for build output
    $ cd build
    $ cmake ..      # generate build scripts
    $ make
    ... build process ...
    $ sudo make install

    Build Your Project Using CMake

    $ cd demo      # project directory
    $ mkdir build  # directory for build output
    $ cd build
    $ cmake ..     # generate build scripts
    $ make
    ... build process ...
    $ ./greet
    Hello, World!

    Build Your Project Manually

    • add the path to libfmt.a as library search path (gcc/clang: -L path)
    • link the library (gcc/clang: -l fmt)
    hello.cpp
    #include <fmt/core.h> 
    int main () {
    }
    $ g++ -I path/to/fmt/include -o greet hello.cpp -L path/to/fmt/build -l fmt
    $ ./greet
    Hello, World!

    Using In Visual Studio

    C:\users\jlp> cd fmt
    C:\users\jlp> md build   # directory for build output
    C:\users\jlp> cd build
    C:\users\jlp> cmake ..   # generate build scripts

    If Visual Studio was installed, CMake should have created a solution named FMT.sln and Project files (e.g. .vcxproj).

    If you don't have Visual Studio installed on the build machine or want to target a specific Visual Studio Version, you need to specify the appropriate CMake generator and platform e.g., cmake -G "Visual Studio 16 2019" -A x64 ..

    • load an existing Visual Studio solution or create a new one
    • add the fmt project: File → Add → Existing Project… and select fmt.vcxproj
    • go to Project → Dependencies and add fmt as a dependency to all projects in the solution that should use fmt
    • go to Project → Properties select section Configuration Properties → C/C++ and add the path to folder fmt/include to the field Additional Include Directories
    • go to Project → Properties select section Configuration Properties → Linker
      • add the library file name fmtd.lib (debug build) or fmt.lib (release build) to the field Additional Dependencies
      • add the path to these library files, e.g. fmt/build/Debug or fmt/build/Release to the field Additional Library Directories

    Using In Xcode

    $ cd fmt
    $ mkdir build   # directory for build output
    $ cd build
    $ cmake ..      # generate build scripts

    If Xcode is installed, CMake should have creaetd an .xcodeproj file.

    If you don't have XCode installed on the build machine you need to specify the appropriate CMake generator cmake -G "Xcode"

    Quick Overview

    fmt::format(string)  std::string
    fmt::format(fmt-stringformat-string, args...arguments...)  std::string
    fmt::format_to(@output, fmt-stringformat-string, args...arguments...)
    auto str = fmt::format("in {}s\n", 47);
    std::cout << str;  // in 47s
    
    fmt::print(string)
    fmt::print(fmt-stringformat-string, arguments...)
    fmt::print(file, format-string, args...arguments...)
    fmt::print("in {}s\n", 47);  // in 47s
    fmt::print(stderr, "error: {}\n", 404);  // error: 404
    

    Headers

    Argument Placeholder{}

    #include <fmt/core.h>
    int i = 7; 
    double d = 3.4;
    std::string s = "text";
    fmt::print("fast {} output\n", s);
    fmt::print("{} times\n", 47);
    fmt::print("{} of {}\n", i, 9);
    fmt::print("{}|{}|{}\n", di5);        
    fmt::print("escaped {{ & }}\n");
    




    fast text output 47 times 7 of 9 7|3.4|5 escaped { & }
    #include <vector>
    #include <array>
    #include <fmt/ranges.h>
    std::vector<double> v {1.2, 5.6, 7.8};
    std::array<int,4> a {2, 3, 4, 5};
    fmt::print("v: {}\n", v);
    fmt::print("a: {}\n", a);
    fmt::print("{}\n", fmt::join(v,"|"));
    





    v: [1.2, 5.6, 7.8] a: [2, 3, 4, 5] 1.2|5.6|7.8

    Indexing / Naming Arguments {id} Arg IDs

    #include <fmt/core.h>
    fmt::print("{}, {}, {}\n", 'a', 'b', 'c');
    fmt::print("{0}, {1}, {2}\n", 'a', 'b', 'c');
    fmt::print("{2}, {1}, {0}\n", 'a', 'b', 'c');
    fmt::print("{0}{1}{0}\n", "XX", "abc");
    int i = 20; 
    double d = 3.4;
    fmt::print("{1} to {0}\n", i, 10);
    fmt::print("{0} / {0}\n", d);
    

    a, b, c a, b, c c, b, a XXabcXX

    10 to 20 3.4 / 3.4
    #include <fmt/format.h>  // literals
    int i = 2; 
    double d = 4.567;
    fmt::print("{x} + {x}\n", fmt::arg("x",d));
    fmt::print("{pi} * {0}\n", i, fmt::arg("pi",3.14));
    using namespace fmt::literals;
    fmt::print("{y} | {x}\n", "x"_a=i, "y"_a=d);
    



    4.567 + 4.567 3.14 * 2
    4.567 | 2

    Format Specifications {:…} Format Specs

    {fmt} format specifications syntax overview
    #include <fmt/core.h>
    int i = 18; 
    fmt::print("{:+}\n", i);    // sign always
    fmt::print("{:b}\n", i);    // binary
    fmt::print("{:x}\n", i);    // hex
    fmt::print("{:#x}\n", i);   // hex+prefix
    


    +18 10010 12 0x12
    fmt::print("{:6}\n", i);    // width 6
    fmt::print("{:06}\n", i);   // 0-prefixed
    fmt::print("{:>6}\n", i);   // align right
    fmt::print("{:*>6}\n", i);  // align right
    fmt::print("{:*^6}\n", i);  // center
    fmt::print("{:*<6}\n", i);  // align left
    
        18
    000018
        18
    ****18
    **18**
    18****
    double d = 34.567;
    fmt::print("{:.3}\n", d);   // precision 3
    fmt::print("{:+8.3}\n", d); // width 8
    fmt::print("{:e}\n", d);    // exponential
    fmt::print("{:.3e}\n", d);  // exp+prec
    fmt::print("{:*>+12.1e}\n", d);
    

    34.6 +34.56 3.456700e+01 3.457e+01 ****+3.5e+01

    Print To File / stderr

    #include <fmt/core.h>
    fmt::print("print to stdout\n");
    fmt::print(stdout, "same");
    fmt::print(stderr, "warning!");
    

    This can be substantially faster than C's fprintf (see here) .

    Overwrite existing file, create file if it doesn't exist (default)

    output_file("name")

    output_file("name", fmt::file::WRONLY | fmt::file::CREATE)

    Append to existing file, create file if it doesn't exist

    output_file("name", fmt::file::WRONLY | fmt::file::CREATE | fmt::file::APPEND)

    Error Handling Errors

    C++20 + {fmt} v8.x C++20

    Default: Compile-Time Checks

    Requires a compiler with full support for consteval.

    #include <fmt/core.h>
    double x = 3.456;
    fmt::print("{0}\n", x);  
    fmt::print("{1}\n", x);   only one arg
    
    $ make
    
    /home/demo/fmt/include/fmt/core.h:2432:40: error: …
    2432 |  if (id >= num_args_) this->on_error("argument not found");
         |                       ~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~
    
    make[1]: *** [CMakeFiles/Makefile2:133: CMakeFiles/errors.dir/all] Error 2                   
    make: *** [Makefile:84: all] Error 2
    Opt-In: Runtime Checks (Throw Exceptions)
    #include <fmt/core.h>
    double x = 3.456;
    fmt::print("{0}\n", x);  
    fmt::print(fmt::runtime("{1}\n"), x);  
    
    $ make
    
    $ ./run-demo
    3.46                                                                    
    terminate called after throwing an instance of 'fmt::v7::format_error'
      what():  argument not found
    Aborted

    C++11-17 and/or {fmt} v7.x Legacy

    Default: Runtime Checks (Throw Exceptions)
    #include <fmt/core.h>
    double x = 3.456;
    fmt::print("{0}\n", x);  
    fmt::print("{1}\n", x);  
    
    $ make
    
    $ ./run-demo
    3.46                                                                    
    terminate called after throwing an instance of 'fmt::v7::format_error'
      what():  argument not found
    Aborted
    Opt-In: Compile Time Checks
    #include <fmt/format.h>
    double x = 3.456;
    fmt::print(FMT_STRING("{0}\n"), x);  
    fmt::print(FMT_STRING("{1}\n"), x);  
    
    $ make
    
    /home/demo/fmt/include/fmt/core.h:2432:40: error: …
    2432 |  if (id >= num_args_) this->on_error("argument not found");
         |                       ~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~
    
    make[1]: *** [CMakeFiles/Makefile2:133: CMakeFiles/errors.dir/all] Error 2                   
    make: *** [Makefile:84: all] Error 2

    {fmt} vs. C++20's std::format

    • names are defined in the fmt namespace instead of std
    • {fmt}'s width calculation doesn't yet (as of v8.0) use grapheme clusterization
    • {fmt} doesn't yet (as of v8.0) support all C++20 chrono types

    How To Print / Format Formatting

    Strings

    #include <vector>
    #include <fmt/format.h>
    fmt::print("some text\n");
    fmt::print("A {} B\n", "and");
    
    std::string w = "or"; fmt::print("A {} B\n", w);
    fmt::print("A{x}B{x}C\n", fmt::arg("x",w));
    std::vector<char> v {'a','b','c','\0'}; fmt::print("{}\n", v.data());
    
    
    some text
    A and B
    
    A or B
    AorBorC
    abc
    {fmt} string type format specifications syntax overview

    Alignment {:>} / Width {:5} Align

    • < align left (default)
    • ^ centered
    • > align right
    #include <fmt/core.h>
    std::string s = "Ab C";
    
    fmt::print("|{}|\n", s);
    fmt::print("|{:8}|\n", s); fmt::print("|{:<8}|\n", s); fmt::print("|{:^8}|\n", s); fmt::print("|{:>8}|\n", s);
    fmt::print("|{: >8}|\n", s); fmt::print("|{:*<8}|\n", s); fmt::print("|{:*^8}|\n", s); fmt::print("|{:*>8}|\n", s);
    
    
    
    |Ab C|
    |Ab C | |Ab C | | Ab C | | Ab C|
    | Ab C| |Ab C****| |**Ab C**| |****Ab C|

    Argument-Determined Width {:{}} Width

    #include <fmt/format.h>
    std::string s = "ab";
    int y = 4;
    
    fmt::print("|{:{}}|\n", s, y);
    fmt::print("|{:{w}}|\n", s, fmt::arg("w",y));
    fmt::print("|{:>{w}}|\n", s, fmt::arg("w",y));
    using namespace fmt::literals; fmt::print("|{:>{w}}|\n", s, "w"_a = y);
    
    
    
    
    |ab |
    |ab |
    | ab|
    | ab|

    Cutoff Width  {:.4}{:.{}}

    #include <fmt/format.h>
    std::string s = "abcde";
    
    fmt::print("{:.0}\n", s); fmt::print("{:.1}\n", s); fmt::print("{:.2}\n", s); fmt::print("{:.3}\n", s); fmt::print("{:.4}\n", s); fmt::print("{:.5}\n", s); fmt::print("{:.6}\n", s);
    fmt::print("{:.{}}\n", s, 2);
    fmt::print("{:.{p}}\n", s, fmt::arg("p",3));
    using namespace fmt::literals; fmt::print("{:.{p}}\n", s, "p"_a=4);
    
    
    
    a ab abc abcd abcde abcde
    ab
    abc
    abcd

    Type Specification  {:s} Type

    #include <fmt/core.h>
    fmt::print("{}\n", "abc");
    fmt::print("{}\n", 12.34);
    
    // only accept strings: fmt::print("{:s}\n", "abc"); fmt::print("{:s}\n", 12.34);

    abc 12.34
    abc terminate called after throwing an instance of 'fmt::v7::format_error' what(): argument not found Aborted

    Characters

    #include <fmt/format.h>
    fmt::print("A {}\n", 'Z');
    char c = 'B';
    fmt::print("A {}\n", c);
    fmt::print("A-{x}-{x}\n", fmt::arg("x",c));
    
    
    Z
    
    A B
    A-B-B
    {fmt} character type format specifications syntax overview

    Alignment {:>} / Width {:5} Align

    #include <fmt/core.h>
    char c = 'B';
    
    fmt::print("|{:3}|\n", c); fmt::print("|{:<3}|\n", c); // left fmt::print("|{:^3}|\n", c); // centered fmt::print("|{:>3}|\n", c); // right
    fmt::print("|{: >3}|\n", c); fmt::print("|{:*<3}|\n", c); // left fmt::print("|{:*^3}|\n", c); // centered fmt::print("|{:*>3}|\n", c); // right
    
    
    
    |B | |B | | B | | B|
    | B| |B**| |*B*| |**B|

    Argument-Determined Width {:{}} Width

    #include <fmt/format.h>
    char c = 'B';
    int y = 3;
    
    fmt::print("|{:{}}|\n", c, y);
    fmt::print("|{:{w}}|\n", c, fmt::arg("w",y));
    fmt::print("|{:>{w}}|\n", c, fmt::arg("w",y));
    using namespace fmt::literals; fmt::print("|{:>{w}}|\n", c, "w"_a = y);
    
    
    
    
    |B |
    |B |
    | B|
    | B|

    Type Specification  {:c} Type

    #include <fmt/core.h>
    fmt::print("{}\n", 'B');
    fmt::print("{}\n", 65);
    
    // only accept strings: fmt::print("{:c}\n", 'B'); fmt::print("{:c}\n", 65); fmt::print("{:c}\n", "str");

    B 65
    B A terminate called after throwing an instance of 'fmt::v7::format_error' what(): argument not found Aborted

    Signed Integers Integers

    #include <fmt/format.h>
    int i = 18;
    fmt::print("{:+06}\n", i);
    fmt::print("{:*>#6x}\n", i);
    
    
    
    +00018
    **0x12
    {fmt} signed integer format specifications syntax overview

    Signs {:+}{:-}{: }

    • + always show sign
    • - show sign only for negative numbers (default)
    •   leading space for positive numbers, minus sign for negative numbers
    #include <fmt/core.h>
    int x = -3;
    int y = 47;
    fmt::print("{} {}\n", x, y);
    fmt::print("{:-} {:-}\n", x, y);
    fmt::print("{:+} {:+}\n", x, y);
    fmt::print("{: } {: }\n", x, y);
    
    
    
    
    -3 47
    -3 47
    -3 +47
    -3  47

    Alignment {:>} / Width {:5} Align

    #include <fmt/core.h>
    int i = -47;
    
    fmt::print("|{:5}|\n", i); fmt::print("|{:<5}|\n", i); // left fmt::print("|{:^5}|\n", i); // centered fmt::print("|{:>5}|\n", i); // right
    fmt::print("|{:*<5}|\n", i); // left fmt::print("|{:*^5}|\n", i); // centered fmt::print("|{:*>5}|\n", i); // right
    // sign-aware zero padding: fmt::print("|{:05}|\n", i);
    
    
    
    | -47| |-47 | | -47 | | -47|
    |-47**| |*-47*| |**-47|
    |-0047|

    Argument-Determined Width {:{}} Width

    #include <fmt/format.h>
    int i = 47;
    int w = 4;
    
    fmt::print("|{:{}}|\n", i, w);
    fmt::print("|{:{w}}|\n", i, fmt::arg("w",w));
    fmt::print("|{:<{w}}|\n", i, fmt::arg("w",w));
    using namespace fmt::literals; fmt::print("|{:<{w}}|\n", i, "w"_a = w);
    
    
    
    
    | 47|
    | 47|
    |47 |
    |47 |

    Locale-Aware Formatting {:L} Locale

    #include <fmt/format.h>
    int i = 10000000;
    fmt::print("{}\n", i);
    auto s = fmt::format(
      std::locale("en_US.UTF-8"),"{:L}", i);
    fmt::print("{}\n", s);
    


    10000000

    10,000,000
    #include <fmt/format.h>
    int i = 10000000;
    std::locale::global(std::locale("en_US.UTF-8"));
    fmt::print("{}\n", i);
    fmt::print("{:L}\n", i);



    10000000 10,000,000

    Type Specifications  {:d} Types

    #include <fmt/core.h>
    int i = -47;
    // decimal (default):
    fmt::print("{}\n", i);
    fmt::print("{:d}\n", i);
    // binary (base 2):
    fmt::print("{:b}\n", i);
    fmt::print("{:#b}\n", i);
    fmt::print("{:#B}\n", i);
    // octal (base 8):
    fmt::print("{:o}\n", i);
    fmt::print("{:#o}\n", i);
    // hexadecimal (base 16):
    fmt::print("{:x}\n", i);
    fmt::print("{:#x}\n", i);
    fmt::print("{:#X}\n", i);
    
    
    
    
    -47
    -47
    
    -101111
    -0b101111
    -0B101111
    
    -57
    -057
    
    -2f
    -0x2f
    -0X2F

    Unsigned Integers Unsigned

    #include <fmt/format.h>
    unsigned u = 18;
    fmt::print("{:06}\n", u);
    fmt::print("{:*>#6x}\n", u);
    
    
    
    00018
    **0x12
    {fmt} unsigned integer format specifications syntax overview

    Alignment {:>} / Width {:5} Align

    #include <fmt/core.h>
    unsigned u =  47;
    
    fmt::print("|{:6}|\n", u); fmt::print("|{:<6}|\n", u); // left fmt::print("|{:^6}|\n", u); // centered fmt::print("|{:>6}|\n", u); // right
    fmt::print("|{:*<6}|\n", u); // left fmt::print("|{:*^6}|\n", u); // centered fmt::print("|{:*>6}|\n", u); // right
    // sign-aware zero padding: fmt::print("|{:06}|\n", u);
    
    
    
    | 47| |47 | | 47 | | 47|
    |47****| |**47**| |****47|
    |000047|

    Argument-Determined Width {:{}} Width

    #include <fmt/format.h>
    unsigned u = 47;
    int w = 4;
    
    fmt::print("|{:{}}|\n", u, w);
    fmt::print("|{:{w}}|\n", u, fmt::arg("w",w));
    fmt::print("|{:<{w}}|\n", u, fmt::arg("w",w));
    using namespace fmt::literals; fmt::print("|{:<{w}}|\n", u, "w"_a = w);
    
    
    
    
    | 47|
    | 47|
    |47 |
    |47 |

    Locale-Aware Formatting {:L} Locale

    #include <fmt/format.h>
    unsigned u = 10000000;
    fmt::print("{}\n", u);
    auto s = fmt::format(
      std::locale("en_US.UTF-8"),"{:L}", u);
    fmt::print("{}\n", s);
    


    10000000

    10,000,000
    #include <fmt/format.h>
    unsigned u = 10000000;
    std::locale::global(std::locale("en_US.UTF-8"));
    fmt::print("{}\n", u);
    fmt::print("{:L}\n", u);



    10000000 10,000,000

    Type Specifications  {:d} Types

    #include <fmt/core.h>
    unsigned u = 47;
    // decimal (default):
    fmt::print("{}\n", u);
    fmt::print("{:d}\n", u);
    // binary (base 2):
    fmt::print("{:b}\n", u);
    fmt::print("{:#b}\n", u);
    fmt::print("{:#B}\n", u);
    // octal (base 8):
    fmt::print("{:o}\n", u);
    fmt::print("{:#o}\n", u);
    // hexadecimal (base 16):
    fmt::print("{:x}\n", u);
    fmt::print("{:#x}\n", u);
    fmt::print("{:#X}\n", u);
    
    
    
    
    47
    47
    
    101111
    0b101111
    0B101111
    
    57
    057
    
    2f
    0x2f
    0X2F

    Floating-Point Numbers FP Nums

    #include <fmt/format.h>
    double d = 3.591;
    fmt::print("{:08.4}\n", d);
    fmt::print("{:*>+10.1e}\n", d);
    
    
    
    0003.591
    **+3.6e+00
    {fmt} floating point number format specifications syntax overview

    Signs {:+}{:-}{: }

    • + always show sign
    • - show sign only for negative numbers (default)
    •   leading space for positive numbers, minus sign for negative numbers
    #include <fmt/core.h>
    double x = -3.1;
    double y = 4.7;
    fmt::print("{} {}\n", x, y);
    fmt::print("{:-} {:-}\n", x, y);
    fmt::print("{:+} {:+}\n", x, y);
    fmt::print("{: } {: }\n", x, y);
    
    float inf = std::numeric_limits<float>::infinity(); float nan = std::numeric_limits<float>::quiet_NaN(); fmt::print("{} {}\n", inf, nan); fmt::print("{:+} {:+}\n", inf, nan); fmt::print("{: } {: }\n", inf, nan);
    
    
    
    -3.1 4.7
    -3.1 4.7
    -3.1 +4.7
    -3.1  4.7
    
    inf nan +inf +nan inf nan

    Alignment {:>} / Width {:5} Align

    #include <fmt/core.h>
    double x = 12.345;
    
    fmt::print("|{:8}|\n", x); fmt::print("|{:<8}|\n", x); fmt::print("|{:^8}|\n", x); fmt::print("|{:>8}|\n", x);
    fmt::print("|{:*<8}|\n", x); fmt::print("|{:*^8}|\n", x); fmt::print("|{:*>8}|\n", x);
    // sign-aware zero padding: fmt::print("|{:08}|\n", -5.6);
    
    
    
    | 12.345| |12.345 | | 12.345 | | 12.345|
    |12.345**| |*12.345*| |**12.345|
    |-00005.6|

    Argument-Determined Width {:{}} Width

    #include <fmt/format.h>
    double x = 1.2;
    int w = 5;
    
    fmt::print("|{:{}}|\n", x, w);
    fmt::print("|{:{w}}|\n", x, fmt::arg("w",w));
    fmt::print("|{:>{w}}|\n", x, fmt::arg("w",w));
    using namespace fmt::literals; fmt::print("|{:>{w}}|\n", x, "w"_a = w);
    
    
    
    
    |1.2 |
    |1.2 |
    | 1.2|
    | 1.2|

    Precision {:.4}{:.{}}

    #include <fmt/format.h>
    double x = 12.345;
    
    fmt::print("{:.0}\n", x); fmt::print("{:.1}\n", x); fmt::print("{:.2}\n", x); fmt::print("{:.3}\n", x); fmt::print("{:.4}\n", x); fmt::print("{:.5}\n", x); fmt::print("{:.6}\n", x);
    fmt::print("{:6.3}\n", x); // width 6, prec 3 fmt::print("{:06.3}\n", x); // 0-prefixed
    
    
    
    10 1e+01 12 12.3 12.35 12.345 12.345
    12.3 0012.3
    // precision determined by argument
    fmt::print("{:.{}}\n", x, 2);
    
    fmt::print("{:.{p}}\n", x, fmt::arg("p",3));
    using namespace fmt::literals; fmt::print("{:.{p}}\n", x, "p"_a=4);
    
    12
    
    12.3
    12.34
    // with exponential format
    fmt::print("{:.0e}\n", x);
    fmt::print("{:.1e}\n", x);
    fmt::print("{:.2e}\n", x);
    fmt::print("{:.3e}\n", x);
    fmt::print("{:.4e}\n", x);
    fmt::print("{:.5e}\n", x);
    fmt::print("{:.6e}\n", x);
    
    1e+01
    1.2e+01
    1.23e+01
    1.235e+01
    1.2345e+01
    1.23450e+01
    1.234500e+01

    Locale-Aware Formatting {:L} Locale

    #include <fmt/format.h>
    double x = 123.45;
    fmt::print("{}\n", x);
    auto s = fmt::format(
      std::locale("de_DE.UTF-8"),"{:L}", x);
    fmt::print("{}\n", s);
    


    123.45

    123,45
    #include <fmt/format.h>
    double x = 123.45;
    std::locale::global(std::locale("de_DE.UTF-8"));
    fmt::print("{}\n", x);
    fmt::print("{:L}\n", x);



    123.45 123,45

    Type Specifications  {:g} Types

    #include <fmt/core.h>
    double x = 12.345;
    // general (default):
    fmt::print("{}\n", x);
    fmt::print("{:g}\n", x);
    fmt::print("{:g}\n", 100000000.);
    fmt::print("{:G}\n", 100000000.);
    // scientific notation:
    fmt::print("{:e}\n", x);
    fmt::print("{:E}\n", x);
    // fixed point notation:
    fmt::print("{:f}\n", x);
    fmt::print("{:f}\n", 1./0);
    fmt::print("{:F}\n", 1./0);
    // force decimal point / trailing 0s:
    fmt::print("{:}\n", 1.0);
    fmt::print("{:#}\n", 1.0);
    // hexadecimal (base 16):
    fmt::print("{:a}\n", x);
    fmt::print("{:A}\n", x);
    
    
    
    
    12.345                
    12.345                
    1e+08
    1E+08
    
    1.234500e+01          
    1.234500E+01          
    
    12.345000
    inf
    INF
    
    1
    1.0
    
    0x1.8b0a3d70a3d71p+3  
    0X1.8B0A3D70A3D71P+3

    Booleans bool

    #include <fmt/core.h>
    bool t = true;
    fmt::print("{}\n", t);
    fmt::print("{:d}\n", t);
    fmt::print("{}\n", false);
    
    
    
    true
    1
    false
    {fmt} bool format specifications syntax overview

    Alignment {:>} / Width {:5} Align

    #include <fmt/core.h>
    bool b = true;
    
    fmt::print("|{:6}|\n", b); fmt::print("|{:<6}|\n", b); // left fmt::print("|{:^6}|\n", b); // centered fmt::print("|{:>6}|\n", b); // right
    fmt::print("|{: >6}|\n", b); fmt::print("|{:*<6}|\n", b); // left fmt::print("|{:*^6}|\n", b); // centered fmt::print("|{:*>6}|\n", b); // right
    
    
    
    |true | |true | | true | | true|
    | true| |true**| |*true*| |**true|

    Argument-Determined Width {:{}} Width

    #include <fmt/format.h>
    bool b = true;
    int y = 6;
    
    fmt::print("|{:{}}|\n", b, y);
    fmt::print("|{:{w}}|\n", b, fmt::arg("w",y));
    fmt::print("|{:>{w}}|\n", b, fmt::arg("w",y));
    using namespace fmt::literals; fmt::print("|{:>{w}}|\n", b, "w"_a = y);
    
    
    
    
    |true |
    |true |
    | true|
    | true|

    Type Specification  {:d} Type

    #include <fmt/core.h>
    bool b = true;
    
    fmt::print("{}\n", b); fmt::print("{:s}\n", b); fmt::print("{:d}\n", b);
    fmt::print("{:b}\n", b); fmt::print("{:#b}\n", b); fmt::print("{:#B}\n", b);
    fmt::print("{:o}\n", b); fmt::print("{:#o}\n", b);
    fmt::print("{:x}\n", b); fmt::print("{:#x}\n", b); fmt::print("{:#X}\n", b);
    
    
    
    true true 1
    1 0b1 0B1
    1 01
    1 0x1 0X1

    Pointer Values Pointers

    #include <fmt/format.h>
    int i = 12;
    int* pi = &i;
    fmt::print("{}\n", fmt::ptr(&i));
    fmt::print("{}\n", fmt::ptr(pi));
    
    
    
    
    0x7ffe55a4e7ac
    0x7ffe55a4e7ac
    {fmt} pointer value format specifications syntax overview

    Alignment {:>} / Width {:5} Align

    #include <fmt/format.h>
    int i = 12;
    int* pi = &i;
    auto const p = fmt::ptr(pi);
    
    fmt::print("|{:18}|\n", p); fmt::print("|{:<18}|\n", p); fmt::print("|{:^18}|\n", p); fmt::print("|{:>18}|\n", p);
    fmt::print("|{: >18}|\n", p); fmt::print("|{:*<18}|\n", p); fmt::print("|{:*^18}|\n", p); fmt::print("|{:*>18}|\n", p);
    
    
    
    
    
    | 0x7ffe55a4e7ac| |0x7ffe55a4e7ac | | 0x7ffe55a4e7ac | | 0x7ffe55a4e7ac|
    | 0x7ffe55a4e7ac| |0x7ffe55a4e7ac****| |**0x7ffe55a4e7ac**| |****0x7ffe55a4e7ac|

    Argument-Determined Width {:{}} Width

    #include <fmt/format.h>
    int i = 12;
    int* pi = &i;
    auto const p = fmt::ptr(pi);
    int const w = 18;
    
    fmt::print("|{:{}}|\n", p, w);
    fmt::print("|{:{w}}|\n", p, fmt::arg("w",w));
    fmt::print("|{:<{w}}|\n", p, fmt::arg("w",w));
    using namespace fmt::literals; fmt::print("|{:<{w}}|\n", p, "w"_a = w);
    
    
    
    
    
    
    | 0x7ffe55a4e7ac|
    | 0x7ffe55a4e7ac|
    |0x7ffe55a4e7ac |
    |0x7ffe55a4e7ac |

    Type Specification  {:p} Type

    #include <fmt/format.h>
    int i = 12;
    
    fmt::print("{}\n", fmt::ptr(&i));
    fmt::print("{:p}\n", fmt::ptr(&i));
    fmt::print("{:p}\n", 123);
    
    
    
    0x7ffe55a4e7ac
    0x7ffe55a4e7ac
    terminate called after throwing an instance of 'fmt::v7::format_error' what(): argument not found Aborted

    Tuples (std::pair, std::tuple)

    std::pair

    #include <utility>  // pair
    #include <fmt/ranges.h>
    std::pair<char,int> t {'a', 2};
    fmt::print("{}\n", t);
    
    
    
    
    ('a', 2)

    std::tuple

    #include <tuple>
    #include <fmt/ranges.h>
    std::tuple<char,int,double> t {'a', 2, 3.4};
    fmt::print("{}\n", t);
    fmt::print("{}\n", fmt::join(t,"|"));
    fmt::print("{}\n", fmt::join(t,""));
    
    
    
    
    ('a', 2, 3.4)
    a|2|3.4
    a23.4

    Containers / Ranges (std::vector, …) Ranges

    #include <vector>
    #include <fmt/ranges.h>
    std::vector<int> v {2,3,4,5};
    fmt::print("{}\n", v);
    fmt::print("{}\n", fmt::join(v,"|"));
    fmt::print("{:03}\n", fmt::join(v,"|"));
    
    
    
    
    [2, 3, 4, 5]
    2|3|4|5
    002|003|004|005
    #include <array>
    #include <fmt/ranges.h>
    std::array<int,4> a {2,3,4,5};
    fmt::print("{}\n", a);
    fmt::print("{}\n", fmt::join(a," | "));
    
    
    
    
    [2, 3, 4, 5]
    2 | 3 | 4 | 5
    #include <set>
    #include <fmt/ranges.h>
    std::set<int> s {2,3,4,5};
    fmt::print("{}\n", s);
    fmt::print("{}\n", fmt::join(s,""));
    
    
    
    
    [2, 3, 4, 5]
    2345
    #include <map>
    #include <fmt/ranges.h>
    std::map<char,int> m {{'a',2},{'b',4}};
    fmt::print("{}\n", m);
    fmt::print("{}\n", fmt::join(m,""));
    
    
    
    
    [('a', 2),('b', 4)]
    ('a', 2)('b', 4)

    Time / Dates

    std::chrono::time_point

    #include <fmt/chrono.h>
    auto now = std::chrono::system_clock::now();
    fmt::print("{}\n", now);
    fmt::print("{:%S}\n", now);
    fmt::print("{:%d/%m}\n", now);
    


    2021-07-04 18:03:09 09 07/04

    C Time Types

    #include <fmt/chrono.h>
    std::time_t tp = std::time(nullptr);             
    auto const t = fmt::localtime(tp);
    fmt::print("{}\n", t);    // no output
    fmt::print("{:%D}\n", t); // %m/%d/%y
    fmt::print("{:%F}\n", t); // ISO 8601
    




    07/04/21 2021-07-04

    Chrono Tokens{:%…}

    The chrono format syntax follows that of std::strftime and is also used by std::format.

    #include <fmt/chrono.h>
    auto const t = std::chrono::system_clock::now();
    
    fmt::print("{}\n", t);
    fmt::print("{:%Y-%m-%d}\n", t); 
    
    fmt::print("{:%F}\n", t); // ISO 8601 fmt::print("{:%D}\n", t); // %m/%d/%y
    fmt::print("{:%c}\n", t); // localized
    2021-07-04 18:03:09
    2021-07-04
    
    2021-07-04 07/04/21
    Sun Jul 4 18:03:09 2021
    fmt::print("{:%y}\n", t); // year
    fmt::print("{:%Y}\n", t); // year
    21
    2021
    fmt::print("{:%m}\n", t); // month
    fmt::print("{:%b}\n", t); 
    fmt::print("{:%B}\n", t);
    07
    Jul
    July
    fmt::print("{:%d}\n", t); // day of month
    fmt::print("{:%a}\n", t); 
    fmt::print("{:%A}\n", t);
    04
    Sun
    Sunday
    fmt::print("{:%u}\n", t); // weekday
    fmt::print("{:%w}\n", t); // weekday (US)
    fmt::print("{:%j}\n", t); // day of year
    7
    0
    185
    fmt::print("{:%H}\n", t); // /24 hours
    fmt::print("{:%M}\n", t); // minutes
    fmt::print("{:%S}\n", t); // seconds
    fmt::print("{:%T}\n", t); // %H:%M:%S
    fmt::print("{:%I}\n", t); // /12 hours
    fmt::print("{:%p}\n", t); // AM/PM
    18
    03
    09
    18:03:09
    06
    PM
    separate compilation example

    Custom Types

    {fmt} can print types that support iostream

    i.e., types T for which an operator << (std::ostream&, T const&) is defined

    #include <fmt/ostream.h>
    
    struct point2d {
      int x;
      int y;
      point2d(int x_, int y_): x(x_), y(y_) {}
      friend std::ostream&   operator << (std::ostream& os, point2d const& p)   {
        return os << '(' << p.x << ',' << p.y << ')';
      }
    };
    
    std::string s = fmt::format("Position is {}", point2d{7,9});
    // s = "Position is (7,9)"
    

    Any type T can be made formattable/printable by specializing template fmt::formatter<T>.

    If a type provides both a formatter specialization and an implicit conversion to an already formattable type, the specialization takes precedence over the conversion.

    C++20's std::format works similarly, it uses specializations of std::formatter.

    Fully Custom Formatter

    struct Point { double x, y; };
    template <>
    class fmt::formatter<Point> {
      // format specification storage
      char presentation_ = 'f';
    public:
      // parse format specification and store it:
      constexpr auto   parse (format_parse_context& ctx) {     auto i = ctx.begin(), end = ctx.end();
        if (i != end && (*i == 'f' || *i == 'e')) {
          presentation_ = *i++;
        }
        if (i != end && *i != '}') {
          throw format_error(        "invalid format");
        }
        return i;  }
      // format a value using stored specification:
      template <typename FmtContext>
      constexpr auto   format (Point const& p,           FmtContext& ctx) const {     // note: we can't use ternary operator '?:' in a constexpr
        switch (presentation_) {
        default:
        // 'ctx.out()' is an output iterator
        case 'f': return format_to(ctx.out(),               "({:f}, {:f})", p.x, p.y);
        case 'e': return format_to(ctx.out(),               "({:e}, {:e})", p.x, p.y);
        }  }
    };
    int main () {
      Point p {1.2, 3.4};
      fmt::print("{}\n", p);
      fmt::print("{:f}\n", p);
      fmt::print("{:e}\n", p);
    }
    (1.2, 3.4)
    (1.2, 3.4)
    (1.2e+00, 3.4e+00)

    Inheriting From Existing Formatter

    enum class color {red, green, blue};
    template <>
    struct fmt::formatter<color> :   formatter<string_view>
    {
      // use inherited 'formatter<string_view>::parse'…
      // … and only implement 'format':
      template <typename FmtContext>
      auto format (color c, FmtContext& ctx) {
        string_view name = "unknown";
        switch (c) {
          case color::red:         name = "red"; break;
          case color::green:       name = "green"; break;
          case color::blue:        name = "blue"; break;
        }
        return formatter<string_view>::format(name, ctx);
      }
    };
    int main () {
      fmt::print("|{:>10}|\n", color::blue);
    }
    |      blue|

    Colorizing / Styling (Terminal) Colorize/Style

    #include <fmt/color.h>
    std::string s = "Abc\n";
    
    fmt::print(fmt::emphasis::bold, s);                                              
    fmt::print(fmt::emphasis::italic, s);                                            
    fmt::print(fmt::emphasis::bold | fmt::emphasis::italic, s);
    Abc
    Abc
    Abc
    fmt::print(fg(fmt::color::red), s);                                              
    fmt::print(fg(fmt::color::green), s);                                            
    fmt::print(fg(fmt::color::blue), s);
    Abc
    Abc
    Abc
    fmt::print(bg(fmt::color::red), s);                                              
    fmt::print(bg(fmt::color::green), s);                                            
    fmt::print(bg(fmt::color::blue), s);
    Abc
    Abc
    Abc
    fmt::print(fmt::emphasis::bold | bg(fmt::color::red), s);
    Abc
    fmt::print(fmt::emphasis::bold | fmt::emphasis::italic | bg(fmt::color::red), s);
    Abc

    Locale-Aware Formatting

    Only available for numeric types: int, float, double, bool, char, …

    Integers

    #include <fmt/format.h>
    int i = 10000000;
    fmt::print("{}\n", i);
    auto s = fmt::format(
      std::locale("en_US.UTF-8"),"{:L}", i);
    fmt::print("{}\n", s);
    


    10000000

    10,000,000
    #include <fmt/format.h>
    int i = 10000000;
    std::locale::global(std::locale("en_US.UTF-8"));
    fmt::print("{}\n", i);
    fmt::print("{:L}\n", i);



    10000000 10,000,000

    Floating-Point Numbers FP Nums

    #include <fmt/format.h>
    double x = 123.45;
    fmt::print("{}\n", x);
    auto s = fmt::format(
      std::locale("de_DE.UTF-8"),"{:L}", x);
    fmt::print("{}\n", s);
    


    123.45

    123,45
    #include <fmt/format.h>
    double x = 123.45;
    std::locale::global(std::locale("de_DE.UTF-8"));
    fmt::print("{}\n", x);
    fmt::print("{:L}\n", x);



    123.45 123,45

    Compile Time Formatting

    Does (as of {fmt} v8) not yet work for floating-point numbers and pointers.

    #include <fmt/compile.h>
    
    consteval std::array<char,5> compile_time_itoa (int value) {
      auto result = std::array<char,5>{};
      fmt::format_to(result.data(), FMT_COMPILE("{}"), value);
      return result;
    }
    
    constexpr auto s = compile_time_itoa(37);
    // s = {'3','7',' ',' ',' '}
    

    Custom Formatting Functions

    fmt::format_args and associated types can be used to pass argument lists to custom formatting functions. This helps to achieve reduced binary code sizes compared to fully parametrized functions.

    vprint / vformat

    fmt::vprint(target, fmt::string_view, fmt::format_args)

    fmt::vformat(fmt::string_view, fmt::format_args)

    fmt::make_format_args(arguments…) fmt::format_arg_store

    #include <fmt/format.h>
    fmt::vprint("{}\n", fmt::make_format_args(47));
    fmt::vprint("{} of {}\n", fmt::make_format_args("seven", 9));
    
    47
    seven of 9

    Example: Formatted HTML Comment Printing

    fmt::make_args_checked(str, arguments…) fmt::format_arg_store

    • makes a format_arg_store that contains references to arguments
    • a format_arg_store can be implicitly converted to format_args
    • if str is a compile-time string then its validity is checked at compile time
    #include <fmt/format.h>
    void vcomment (fmt::string_view format, fmt::format_args args) {
      fmt::print("<-- ");
      fmt::vprint(format, args);
      fmt::print(" -->\n");
    }
    template <typename Str, typename... Args>
    void comment (Str const& format, Args&&... args) {
      vcomment(format, fmt::make_args_checked<Args...>(format, args...));
    }
    int main () {
      double const d = 12.345;
      comment("{:e} and {}", d, 47);
    }
    <!-- 1.234500e+01 and 47 -->

    Memory Management

    format_to (@out, fmtstr, args…)

    format_to(@target, format-string, arguments...)

    #include <fmt/format.h>
    double const d = 123.45678;
    fmt::memory_buffer buf;
    format_to(std::back_inserter(buf), "{:e}", d);
    auto ptrToFormattedData  = buf.data();
    auto sizeOfFormattedData = buf.size();
    auto str = to_string(buf);  // std::string str = "1.234568e+02";
    
    std::vector<char> vc;
    fmt::format_to(std::back_inserter(vc), "{:e}", d);
    // vc = {'1','.','2','3','4','5','6','8','e','+','0','2'}
    

    format_to_n (@out, n, fmtstr, args…)

    format_to_n(@target, size, format-string, arguments...)

    #include <fmt/format.h>
    double const d = 123.45678;
    constexpr int N = 15;
    std::array<char,N> a;  // initialized with 0s!
    fmt::format_to_n(a.data(), N, "{:e}", d);
    // a = {'1','.','2','3','4','5','6','8','e','+','0','2',0,0,0}
    

    formatted_size (fmtstr, args…)

    formatted_size(format-string, arguments...) size of formatted result

    #include <fmt/format.h>
    double const d = 123.45678;
    auto size = fmt::formatted_size("{:e}", d);  // size = 12
    

    Custom Allocators

    • the allocator will be used for the output container only
    • formatting functions normally don't do any allocations for built-in and string types (except for non-default floating-point formatting that occasionally falls back to sprintf)
    #include <fmt/format.h>
    
    // simple allocator that delegates to new/delete
    template <class T> 
    struct naive_allocator { 
      using value_type = T; 
      template<class U> struct rebind { using other = naive_allocator<U>; };
      T*   allocate(std::size_t n) { return new T[n]; }
      void deallocate(T* p, std::size_t) { delete[] p; } 
    };         
    using my_allocator = naive_allocator<char>;
    
    // string that uses custom allocator using my_string = std::basic_string< char, std::char_traits<char>, my_allocator>; // format buffer that uses custom allocator using my_buffer = fmt::basic_memory_buffer< char, fmt::inline_buffer_size, my_allocator>;
    my_string vformat ( my_allocator alloc, fmt::string_view str, fmt::format_args args) { // temp. buffer for formatting my_buffer buf(alloc); vformat_to(buf, str, args); // result string uses custom allocator return my_string(buf.data(), buf.size(), alloc); } template <typename... Args> my_string format ( my_allocator alloc, fmt::string_view str, Args const&... args) { return vformat(alloc, str, fmt::make_format_args(args...)); }
    int main () { my_allocator alloc; auto s = format(alloc, "{} of {}", "seven", 9); // my_string s = "seven of 9"; }

    Cheat Sheets

    {fmt} – Printing & Formatting

    (click to enlarge)

    {fmt} – Time & Date Formatting

    std::format and std::strftime use the same formatting tokens