{fmt} Formatting & Printing Library {fmt} Formatting & Printing Library {fmt}
A fast and safe alternative to C stdio and C++ iostreams
- faster than common implementations of iostreams,
(s)printf
,to_string
andto_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
Setup (Install, Compile, …)
hello.cpp
// header-only mode not needed in compiler explorer:
// #define FMT_HEADER_ONLY
#include <fmt/core.h>
int main () {
fmt::print("Hello, World!\n");
}
Example Project Layout
demo/
hello.cpp
fmt/
include/
fmt/
core.h
…
src/
…
$ 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/
.
demo/hello.cpp
#include <fmt/core.h>
int main () {
fmt::print("Hello, World!\n");
}
demo/CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(FmtDemo)
add_subdirectory(fmt)
add_executable(greet hello.cpp)
# set to C++17 (not required)
set_property(TARGET greet PROPERTY CXX_STANDARD 17)
target_link_libraries(greet fmt::fmt)
Project Layout
demo/
CMakeLists.txt
hello.cpp
fmt/
doc/
include/
src/
support/
test/
CMakeLists.txt
…
$ 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!
Build {fmt} Library (Using CMake)
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
CMake
demo/hello.cpp
#include <fmt/core.h>
int main () {
fmt::print("Hello, World!\n");
}
demo/CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(FmtDemo)
find_package(fmt)
add_executable(greet hello.cpp)
# set to C++17 (not required)
set_property(TARGET greet PROPERTY CXX_STANDARD 17)
target_link_libraries(greet fmt::fmt)
$ cd demo # project directory
$ mkdir build # directory for build output
$ cd build
$ cmake .. # generate build scripts
$ make
... build process ...
$ ./greet
Hello, World!
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!
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) orfmt.lib
(release build) to the field Additional Dependencies - add the path to these library files,
e.g.
fmt/build/Debug
orfmt/build/Release
to the field Additional Library Directories
- add the library file name
1. Create {fmt} Project Using CMake
$ 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"
2. Add fmt.xcodeproj
To Your Workspace
Quick Overview
Formatting
fmt::format(string) → std::string
fmt::format(fmt-stringformat-string, args...arguments...) → std::string
fmt::format_to(@output, fmt-stringformat-string, args...arguments...)
#include <fmt/core.h>
#include <iostream>
int main () {
auto str = fmt::format("in {}s\n", 47);
std::cout << str; // in 47s
}
Printing
fmt::print(string)
fmt::print(fmt-stringformat-string, arguments...)
fmt::print(file, format-string, args...arguments...)
#include <fmt/core.h>
int main () {
fmt::print("in {}s\n", 47); // in 47s
fmt::print(stderr, "error: {}\n", 404); // error: 404
}
<fmt/core.h> |
lightweight subset of formatting API |
<fmt/format.h> |
full API = core.h + compile-time format checks, iterators, user-def. types, … |
<fmt/args.h> |
core.h + dynamic format arguments |
<fmt/chrono.h> |
format.h + date and time formatting |
<fmt/compile.h> |
format.h + format string compilation |
<fmt/color.h> |
format.h + terminal color and text style |
<fmt/os.h> |
format.h + file output, system APIs |
<fmt/ostream.h> |
format.h + std::ostream support |
<fmt/printf.h> |
format.h + printf formatting |
<fmt/ranges.h> |
format.h + formatting support for ranges and tuples |
<fmt/xchar.h> |
format.h + wchar_t support |
#include <fmt/core.h>
int main () {
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", d, i, 5);
fmt::print("escaped {{ & }}\n");
}
fast text output
47 times
7 of 9
3.4|7|5
escaped { & }
#include <vector>
#include <array>
#include <fmt/ranges.h>
int main () {
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
#include <fmt/core.h>
int main () {
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 main () {
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
#include <fmt/core.h>
int main () {
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
#include <fmt/core.h>
int main () {
int i = 18;
fmt::print("{:6}\n", i); // width 6
fmt::print("{:06}\n", i); // 0-prefixed
fmt::print("\n");
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****
#include <fmt/core.h>
int main () {
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}\n", ""); // line
fmt::print("{:*>+12.1e}\n", d);
}
34.6
+34.56
3.456700e+01
3.457e+01
------------
****+3.5e+01
More detailed examples are available in the next main section:
#include <fmt/core.h>
int main () {
fmt::print("print to stdout\n");
fmt::print(stdout, "same");
fmt::print(stderr, "warning!");
}
fmt::ostream
/ This can be substantially faster than C's fprintf
(see here)
.
#include <fmt/os.h>
int main () {
fmt::ostream out = fmt::output_file("out.txt");
for (int ln = 0; ln < 4; ++ln) {
out.print("line {}\n", ln);
}
}
out.txt
line·0\n
line·1\n
line·2\n
line·3\n
File Access Control Flags
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)
fmt::print(std::FILE*, …)
#include <cstdio> // fopen
#include <fmt/core.h>
int main () {
std::FILE* file = std::fopen("out.txt","w");
for (int ln = 0; ln < 5; ++ln) {
fmt::print(file, "line {}\n", ln);
}
std::fclose(file);
}
out.txt
line·0\n
line·1\n
line·2\n
line·3\n
line·4\n
Default: Compile-Time Checks
Requires a compiler with full support for consteval
.
#include <fmt/core.h>
int main () {
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>
int main () {
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
Default: Runtime Checks (Throw Exceptions)
#include <fmt/core.h>
int main () {
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>
int main () {
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 ofstd
- {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
#include <vector>
#include <fmt/format.h>
int main () {
fmt::print("some text\n");
fmt::print("A {} B\n", "and");
fmt::print("--------------------\n");
std::string w = "or";
fmt::print("A {} B\n", w);
fmt::print("--------------------\n");
fmt::print("A{x}B{x}C\n", fmt::arg("x",w));
fmt::print("--------------------\n");
std::vector<char> v {'a','b','c','\0'};
fmt::print("{}\n", v.data());
}
some text
A and B
A or B
AorBorC
abc
<
align left (default)^
centered>
align right
#include <fmt/core.h>
int main () {
std::string s = "Ab C";
fmt::print("--------------------\n");
fmt::print("|{}|\n", s);
fmt::print("--------------------\n");
fmt::print("|{:8}|\n", s);
fmt::print("|{:<8}|\n", s);
fmt::print("|{:^8}|\n", s);
fmt::print("|{:>8}|\n", s);
fmt::print("--------------------\n");
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|
#include <fmt/format.h>
int main () {
std::string s = "ab";
int y = 4;
fmt::print("--------------------\n");
fmt::print("|{:{}}|\n", s, y);
fmt::print("--------------------\n");
fmt::print("|{:{w}}|\n", s, fmt::arg("w",y));
fmt::print("--------------------\n");
fmt::print("|{:>{w}}|\n", s, fmt::arg("w",y));
fmt::print("--------------------\n");
using namespace fmt::literals;
fmt::print("|{:>{w}}|\n", s, "w"_a = y);
}
|ab |
|ab |
| ab|
| ab|
#include <fmt/format.h>
int main () {
std::string s = "abcde";
fmt::print("--------------------\n");
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");
fmt::print("{:.{}}\n", s, 2);
fmt::print("--------------------\n");
fmt::print("{:.{p}}\n", s, fmt::arg("p",3));
fmt::print("--------------------\n");
using namespace fmt::literals;
fmt::print("{:.{p}}\n", s, "p"_a=4);
}
a
ab
abc
abcd
abcde
abcde
ab
abc
abcd
#include <fmt/core.h>
int main () {
fmt::print("{}\n", "abc");
fmt::print("{}\n", 12.34);
fmt::print("--------------------\n");
// 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
#include <fmt/format.h>
int main () {
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
#include <fmt/core.h>
int main () {
char c = 'B';
fmt::print("--------------------\n");
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("--------------------\n");
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|
#include <fmt/format.h>
int main () {
char c = 'B';
int y = 3;
fmt::print("--------------------\n");
fmt::print("|{:{}}|\n", c, y);
fmt::print("--------------------\n");
fmt::print("|{:{w}}|\n", c, fmt::arg("w",y));
fmt::print("--------------------\n");
fmt::print("|{:>{w}}|\n", c, fmt::arg("w",y));
fmt::print("--------------------\n");
using namespace fmt::literals;
fmt::print("|{:>{w}}|\n", c, "w"_a = y);
}
|B |
|B |
| B|
| B|
#include <fmt/core.h>
int main () {
fmt::print("{}\n", 'B');
fmt::print("{}\n", 65);
fmt::print("--------------------\n");
// 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
#include <fmt/format.h>
int main () {
int i = 18;
fmt::print("{:+06}\n", i);
fmt::print("{:*>#6x}\n", i);
}
+00018
**0x12
+
always show sign-
show sign only for negative numbers (default)
#include <fmt/core.h>
int main () {
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
#include <fmt/core.h>
int main () {
int i = -47;
fmt::print("--------------------\n");
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("--------------------\n");
fmt::print("|{:*<5}|\n", i); // left
fmt::print("|{:*^5}|\n", i); // centered
fmt::print("|{:*>5}|\n", i); // right
fmt::print("--------------------\n");
// sign-aware zero padding:
fmt::print("|{:05}|\n", i);
}
| -47|
|-47 |
| -47 |
| -47|
|-47**|
|*-47*|
|**-47|
|-0047|
#include <fmt/format.h>
int main () {
int i = 47;
int w = 4;
fmt::print("--------------------\n");
fmt::print("|{:{}}|\n", i, w);
fmt::print("--------------------\n");
fmt::print("|{:{w}}|\n", i, fmt::arg("w",w));
fmt::print("--------------------\n");
fmt::print("|{:<{w}}|\n", i, fmt::arg("w",w));
fmt::print("--------------------\n");
using namespace fmt::literals;
fmt::print("|{:<{w}}|\n", i, "w"_a = w);
}
| 47|
| 47|
|47 |
|47 |
#include <fmt/format.h>
int main () {
int i = 10000000;
fmt::print("{}\n", i);
auto s = fmt::format(
std::locale("en_US.UTF-8"),"{:L}", i);
fmt::print("{}\n", s);
fmt::print("--------------------\n");
std::locale::global(std::locale("en_US.UTF-8"));
fmt::print("{}\n", i);
fmt::print("{:L}\n", i);
}
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
#include <fmt/core.h>
int main () {
int i = -47;
fmt::print("--------------------\n");
// decimal (default):
fmt::print("{}\n", i);
fmt::print("{:d}\n", i);
fmt::print("--------------------\n");
// binary (base 2):
fmt::print("{:b}\n", i);
fmt::print("{:#b}\n", i);
fmt::print("{:#B}\n", i);
fmt::print("--------------------\n");
// octal (base 8):
fmt::print("{:o}\n", i);
fmt::print("{:#o}\n", i);
fmt::print("--------------------\n");
// 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
#include <fmt/format.h>
int main () {
unsigned u = 18;
fmt::print("{:06}\n", u);
fmt::print("{:*>#6x}\n", u);
}
00018
**0x12
#include <fmt/core.h>
int main () {
unsigned u = 47;
fmt::print("--------------------\n");
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("--------------------\n");
fmt::print("|{:*<6}|\n", u); // left
fmt::print("|{:*^6}|\n", u); // centered
fmt::print("|{:*>6}|\n", u); // right
fmt::print("--------------------\n");
// sign-aware zero padding:
fmt::print("|{:06}|\n", u);
}
| 47|
|47 |
| 47 |
| 47|
|47****|
|**47**|
|****47|
|000047|
#include <fmt/format.h>
int main () {
unsigned u = 47;
int w = 4;
fmt::print("--------------------\n");
fmt::print("|{:{}}|\n", u, w);
fmt::print("--------------------\n");
fmt::print("|{:{w}}|\n", u, fmt::arg("w",w));
fmt::print("--------------------\n");
fmt::print("|{:<{w}}|\n", u, fmt::arg("w",w));
fmt::print("--------------------\n");
using namespace fmt::literals;
fmt::print("|{:<{w}}|\n", u, "w"_a = w);
}
| 47|
| 47|
|47 |
|47 |
#include <fmt/format.h>
int main () {
unsigned u = 10000000;
fmt::print("{}\n", u);
auto s = fmt::format(
std::locale("en_US.UTF-8"),"{:L}", u);
fmt::print("{}\n", s);
fmt::print("--------------------\n");
std::locale::global(std::locale("en_US.UTF-8"));
fmt::print("{}\n", u);
fmt::print("{:L}\n", u);
}
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
#include <fmt/core.h>
int main () {
unsigned u = 47;
fmt::print("--------------------\n");
// decimal (default):
fmt::print("{}\n", u);
fmt::print("{:d}\n", u);
fmt::print("--------------------\n");
// binary (base 2):
fmt::print("{:b}\n", u);
fmt::print("{:#b}\n", u);
fmt::print("{:#B}\n", u);
fmt::print("--------------------\n");
// octal (base 8):
fmt::print("{:o}\n", u);
fmt::print("{:#o}\n", u);
fmt::print("--------------------\n");
// 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
#include <fmt/format.h>
int main () {
double d = 3.591;
fmt::print("{:08.4}\n", d);
fmt::print("{:*>+10.1e}\n", d);
}
0003.591
**+3.6e+00
+
always show sign-
show sign only for negative numbers (default)
#include <fmt/core.h>
int main () {
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
#include <fmt/core.h>
int main () {
double x = 12.345;
fmt::print("--------------------\n");
fmt::print("|{:8}|\n", x);
fmt::print("|{:<8}|\n", x);
fmt::print("|{:^8}|\n", x);
fmt::print("|{:>8}|\n", x);
fmt::print("--------------------\n");
fmt::print("|{:*<8}|\n", x);
fmt::print("|{:*^8}|\n", x);
fmt::print("|{:*>8}|\n", x);
fmt::print("--------------------\n");
// 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|
#include <fmt/format.h>
int main () {
double x = 1.2;
int w = 5;
fmt::print("--------------------\n");
fmt::print("|{:{}}|\n", x, w);
fmt::print("--------------------\n");
fmt::print("|{:{w}}|\n", x, fmt::arg("w",w));
fmt::print("--------------------\n");
fmt::print("|{:>{w}}|\n", x, fmt::arg("w",w));
fmt::print("--------------------\n");
using namespace fmt::literals;
fmt::print("|{:>{w}}|\n", x, "w"_a = w);
}
|1.2 |
|1.2 |
| 1.2|
| 1.2|
#include <fmt/format.h>
int main () {
double x = 12.345;
fmt::print("--------------------\n");
// with default format
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("{:.3}\n", 0.5);
fmt::print("{:.1}\n", 0.123);
fmt::print("--------------------\n");
// 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);
fmt::print("--------------------\n");
// width + precision
fmt::print("{:6.3}\n", x); // width 6, prec 3
fmt::print("{:06.3}\n", x); // 0-prefixed
fmt::print("--------------------\n");
// with fixed format
fmt::print("{:.0f}\n", x);
fmt::print("{:.1f}\n", x);
fmt::print("{:.2f}\n", x);
fmt::print("{:.3f}\n", x);
fmt::print("{:.4f}\n", x);
fmt::print("{:.5f}\n", x);
fmt::print("{:.6f}\n", x);
fmt::print("{:.3f}\n", 0.5);
fmt::print("{:.1f}\n", 0.123);
fmt::print("--------------------\n");
// precision determined by argument:
fmt::print("{:.{}}\n", x, 2);
fmt::print("--------------------\n");
fmt::print("{:.{p}}\n", x, fmt::arg("p",3));
fmt::print("--------------------\n");
using namespace fmt::literals;
fmt::print("{:.{p}}\n", x, "p"_a=4);
}
10
1e+01
12
12.3
12.35
12.345
12.345
0.5
0.1
12.3
0012.3
// precision determined by argument
fmt::print("{:.{}}\n", x, 2);
fmt::print("--------------------\n");
fmt::print("{:.{p}}\n", x, fmt::arg("p",3));
fmt::print("--------------------\n");
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
// with fixed format
fmt::print("{:.0f}\n", x);
fmt::print("{:.1f}\n", x);
fmt::print("{:.2f}\n", x);
fmt::print("{:.3f}\n", x);
fmt::print("{:.4f}\n", x);
fmt::print("{:.5f}\n", x);
fmt::print("{:.6f}\n", x);
fmt::print("{:.3f}\n", 0.5);
fmt::print("{:.1f}\n", 0.123);
12
12.3
12.35
12.345
12.3450
12.34500
12.345000
0.500
0.1
#include <fmt/format.h>
int main () {
double x = 123.45;
fmt::print("{}\n", x);
auto s = fmt::format(
std::locale("de_DE.UTF-8"),"{:L}", x);
fmt::print("{}\n", s);
fmt::print("--------------------\n");
std::locale::global(std::locale("de_DE.UTF-8"));
fmt::print("{}\n", x);
fmt::print("{:L}\n", x);
}
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
#include <fmt/core.h>
int main () {
double x = 12.345;
fmt::print("--------------------\n");
// general (default):
fmt::print("{}\n", x);
fmt::print("{:g}\n", x);
fmt::print("{:g}\n", 100000000.);
fmt::print("{:G}\n", 100000000.);
fmt::print("--------------------\n");
// scientific notation:
fmt::print("{:e}\n", x);
fmt::print("{:E}\n", x);
fmt::print("--------------------\n");
// fixed point notation:
fmt::print("{:f}\n", x);
fmt::print("{:f}\n", 1./0);
fmt::print("{:F}\n", 1./0);
fmt::print("--------------------\n");
// force decimal point / trailing 0s:
fmt::print("{:}\n", 1.0);
fmt::print("{:#}\n", 1.0);
fmt::print("--------------------\n");
// 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
#include <string_view>
#include <limits>
#include <fmt/core.h>
template <typename T>
void print_table (std::string_view label) {
using lim = std::numeric_limits<T>;
fmt::print("{0:-^40}\n{1}\n{0:-^40}\n","",label);
fmt::print("lowest {: .20}\n", lim::lowest());
fmt::print("min {: .20}\n", lim::min());
fmt::print("max {: .20}\n", lim::max());
fmt::print("denorm_min {: .20}\n", lim::denorm_min());
fmt::print("epsilon {: .20}\n", lim::epsilon());
fmt::print("round_error {: .20}\n", lim::round_error());
fmt::print("min_exponent {: }\n", lim::min_exponent);
fmt::print("max_exponent {: }\n", lim::max_exponent);
fmt::print("quiet_NaN {}\n", lim::quiet_NaN());
fmt::print("digits {: }\n", lim::digits);
fmt::print("digits10 {: }\n", lim::digits10);
fmt::print("+0 {: }\n", T(0));
fmt::print("-0 {: }\n", T(-0.0));
}
int main () {
print_table<float>("FLOAT");
print_table<double>("DOUBLE");
print_table<long double>("LONG DOUBLE");
}
----------------------------------------
FLOAT
----------------------------------------
lowest -3.4028234663852885981e+38
min 1.175494350822287508e-38
max 3.4028234663852885981e+38
denorm_min 1.4012984643248170709e-45
epsilon 1.1920928955078125e-07
round_error 0.5
min_exponent -125
max_exponent 128
quiet_NaN nan
digits 24
digits10 6
+0 0
-0 -0
…
#include <fmt/core.h>
int main () {
bool t = true;
fmt::print("{}\n", t);
fmt::print("{:d}\n", t);
fmt::print("{}\n", false);
}
true
1
false
#include <fmt/core.h>
int main () {
bool b = true;
fmt::print("--------------------\n");
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("--------------------\n");
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|
#include <fmt/format.h>
int main () {
bool b = true;
int y = 6;
fmt::print("--------------------\n");
fmt::print("|{:{}}|\n", b, y);
fmt::print("--------------------\n");
fmt::print("|{:{w}}|\n", b, fmt::arg("w",y));
fmt::print("--------------------\n");
fmt::print("|{:>{w}}|\n", b, fmt::arg("w",y));
fmt::print("--------------------\n");
using namespace fmt::literals;
fmt::print("|{:>{w}}|\n", b, "w"_a = y);
}
|true |
|true |
| true|
| true|
#include <fmt/core.h>
int main () {
bool b = true;
fmt::print("--------------------\n");
fmt::print("{}\n", b);
fmt::print("{:s}\n", b);
fmt::print("{:d}\n", b);
fmt::print("--------------------\n");
fmt::print("{:b}\n", b);
fmt::print("{:#b}\n", b);
fmt::print("{:#B}\n", b);
fmt::print("--------------------\n");
fmt::print("{:o}\n", b);
fmt::print("{:#o}\n", b);
fmt::print("--------------------\n");
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
#include <fmt/format.h>
int main () {
int i = 12;
int* pi = &i;
fmt::print("{}\n", fmt::ptr(&i));
fmt::print("{}\n", fmt::ptr(pi));
}
0x7ffe55a4e7ac
0x7ffe55a4e7ac
#include <fmt/format.h>
int main () {
int i = 12;
int* pi = &i;
auto const p = fmt::ptr(pi);
fmt::print("--------------------\n");
fmt::print("|{:18}|\n", p);
fmt::print("|{:<18}|\n", p);
fmt::print("|{:^18}|\n", p);
fmt::print("|{:>18}|\n", p);
fmt::print("--------------------\n");
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|
#include <fmt/format.h>
int main () {
int i = 12;
int* pi = &i;
auto const p = fmt::ptr(pi);
int const w = 18;
fmt::print("--------------------\n");
fmt::print("|{:{}}|\n", p, w);
fmt::print("--------------------\n");
fmt::print("|{:{w}}|\n", p,
fmt::arg("w",w));
fmt::print("--------------------\n");
fmt::print("|{:<{w}}|\n", p,
fmt::arg("w",w));
fmt::print("--------------------\n");
using namespace fmt::literals;
fmt::print("|{:<{w}}|\n", p, "w"_a = w);
}
| 0x7ffe55a4e7ac|
| 0x7ffe55a4e7ac|
|0x7ffe55a4e7ac |
|0x7ffe55a4e7ac |
#include <fmt/format.h>
int main () {
int i = 12;
fmt::print("--------------------\n");
fmt::print("{}\n", fmt::ptr(&i));
fmt::print("--------------------\n");
fmt::print("{:p}\n", fmt::ptr(&i));
fmt::print("--------------------\n");
// fmt::print("{:p}\n", 123); // ERROR
}
0x7ffe55a4e7ac
0x7ffe55a4e7ac
terminate called after throwing an instance of 'fmt::v7::format_error'
what(): argument not found
Aborted
#include <utility> // pair
#include <fmt/ranges.h>
int main () {
std::pair<char,int> t {'a', 2};
fmt::print("{}\n", t);
}
('a', 2)
#include <tuple>
#include <fmt/ranges.h>
int main () {
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
#include <vector>
#include <fmt/ranges.h>
#include <array>
#include <set>
#include <map>
int main () {
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,"|"));
fmt::print("--------------------\n");
std::array<int,4> a {2,3,4,5};
fmt::print("{}\n", a);
fmt::print("{}\n", fmt::join(a," | "));
fmt::print("--------------------\n");
std::set<int> s {2,3,4,5};
fmt::print("{}\n", s);
fmt::print("{}\n", fmt::join(s,""));
fmt::print("--------------------\n");
std::map<char,int> m {{'a',2},{'b',4}};
fmt::print("{}\n", m);
fmt::print("{}\n", fmt::join(m,""));
}
[2, 3, 4, 5]
2|3|4|5
002|003|004|005
#include <array>
#include <fmt/ranges.h>
int main () {
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>
int main () {
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>
int main () {
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)
#include <fmt/chrono.h>
int main () {
auto now = std::chrono::system_clock::now();
fmt::print("{}\n", now);
fmt::print("{:%S}\n", now);
fmt::print("{:%d/%m}\n", now);
using tp = std::chrono::time_point<
std::chrono::system_clock, std::chrono::seconds>;
fmt::print("--------------\n");
fmt::print("{:%S}\n", tp(std::chrono::seconds(47)));
using namespace std::chrono_literals;
fmt::print("{}\n", tp(32s));
fmt::print("{:%S}\n", tp(32s));
}
2021-07-04 18:03:09
09
07/04
#include <fmt/chrono.h>
int main () {
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
The chrono format syntax follows that of
std::strftime
and is also used by
std::format
.
- supports
std::chrono::time_point
- supports
std::tm
(C time type) - does not (yet, as of {fmt} v8.0) support C++20 date types
- precision only for
std::chrono::duration
types with a floating-point representation
#include <fmt/chrono.h>
int main () {
auto const t = std::chrono::system_clock::now();
fmt::print("{}\n", t);
fmt::print("{:%Y-%m-%d}\n", t);
fmt::print("-----------------------------------------------\n");
fmt::print("std. date + time %c {:%c}\n", t);
fmt::print("alt. date + time %Ec {:%Ec}\n", t);
fmt::print("-----------------------------------------------\n");
fmt::print("ISO 8601 date %F {:%F}\n", t);
fmt::print("%m/%d/%y %D {:%D}\n", t);
fmt::print("localized date %x {:%x}\n", t);
fmt::print("alt. date %Ex {:%Ex}\n", t);
fmt::print("-----------------------------------------------\n");
fmt::print("%H:%M:%S %T {:%T}\n", t);
fmt::print("%H:%M %R {:%R}\n", t);
fmt::print("localized 12-hour clock %r {:%r}\n", t);
fmt::print("localized time %X {:%X}\n", t);
fmt::print("alt. time %EX {:%EX}\n", t);
fmt::print("-----------------------------------------------\n");
fmt::print("year (last 2 digits) %y {:%y}\n", t);
fmt::print("year (4 digits) %Y {:%Y}\n", t);
fmt::print("century %C {:%C}\n", t);
fmt::print("alt. localized repr. %Ey {:%Ey}\n", t);
fmt::print("alt. localized repr. %EY {:%EY}\n", t);
fmt::print("ISO 8601 week-based year %G {:%G}\n", t);
fmt::print("ISO 8601 week-based year %g {:%g}\n", t);
fmt::print("-----------------------------------------------\n");
fmt::print("month %m {:%m}\n", t);
fmt::print("locale-dep. %Om {:%Om}\n", t);
fmt::print("-----------------------------------------------\n");
fmt::print("abbrev. name of month %a {:%a}\n", t);
fmt::print("full name of month %A {:%A}\n", t);
fmt::print("-----------------------------------------------\n");
fmt::print("week (1st:Mon) 00-53 %W {:%W}\n", t);
fmt::print("week (1st:Sun) 00-53 %U {:%U}\n", t);
fmt::print("week (ISO 8601) 01-53 %V {:%V}\n", t);
fmt::print("localized numerals %OW {:%OW}\n", t);
fmt::print("localized numerals %OU {:%OU}\n", t);
fmt::print("localized numerals %OV {:%OV}\n", t);
fmt::print("-----------------------------------------------\n");
fmt::print("2-digit day of month %d {:%d}\n", t);
fmt::print("1-digit day of month %e {:%e}\n", t);
fmt::print("localized numerals %Od {:%Od}\n", t);
fmt::print("localized numerals %Oe {:%Oe}\n", t);
fmt::print("-----------------------------------------------\n");
fmt::print("weekday (Mon:1 - Sun:7) %u {:%u}\n", t);
fmt::print("weekday (Sun:0 - Sat:6) %w {:%w}\n", t);
fmt::print("local. (Mon:1 - Sun:7) %Ou {:%Ou}\n", t);
fmt::print("local. (Sun:0 - Sat:6) %Ow {:%Ow}\n", t);
fmt::print("-----------------------------------------------\n");
fmt::print("abbrev. name of day %b {:%b}\n", t);
fmt::print("full name of day %B {:%B}\n", t);
fmt::print("-----------------------------------------------\n");
fmt::print("day of year %j {:%j}\n", t);
fmt::print("-----------------------------------------------\n");
fmt::print("hours (24-based) %H {:%H}\n", t);
fmt::print("hours (12-based) %I {:%I}\n", t);
fmt::print("localized numerals %OH {:%OH}\n", t);
fmt::print("localized numerals %OI {:%OI}\n", t);
fmt::print("-----------------------------------------------\n");
fmt::print("minutes %M {:%M}\n", t);
fmt::print("localized numerals %OM {:%OM}\n", t);
fmt::print("-----------------------------------------------\n");
fmt::print("seconds %S {:%S}\n", t);
fmt::print("localized numerals %OS {:%OS}\n", t);
fmt::print("-----------------------------------------------\n");
fmt::print("offset from UTC %z {:%z}\n", t);
fmt::print("time zone abbrev. %Z {:%Z}\n", t);
}
fmt::print("{}\n", t);
fmt::print("{:%Y-%m-%d}\n", t);
fmt::print("--------------------\n");
fmt::print("{:%F}\n", t); // ISO 8601
fmt::print("{:%D}\n", t); // %m/%d/%y
fmt::print("--------------------\n");
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
i.e., types T for which an
operator << (std::ostream&, T const&)
is defined
#include <iostream>
#include <string>
#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 << ')';
}
};
int main () {
std::string s = fmt::format("Position is {}", point2d{7,9});
// s = "Position is (7,9)"
std::cout << s << '\n';
fmt::print("{}\n", s);
}
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
.
#include <fmt/format.h>
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)
#include <fmt/format.h>
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|
A custom container / range type T
needs
- either member functions
T::begin()
andT::end()
- or free standing functions
begin(T const&)
andend(T const&)
that return iterators or pointers whose value type is supported by {fmt} or for which a custom {fmt}-formatter is defined.
Example 1: Wrapper around a standard container
value type of iterator is int
which is printable by {fmt}
#include <vector>
#include <fmt/ranges.h>
class IntList {
std::vector<int> v_;
public:
explicit
IntList (std::initializer_list<int> il): v_{il} {}
[[nodiscard]] auto begin () const noexcept { return v_.begin(); }
[[nodiscard]] auto end () const noexcept { return v_.end(); }
};
int main () {
IntList l {4,8,15,16,23,42};
fmt::print("numbers: {}\n", l);
}
numbers: [4, 8, 15, 16, 23, 24]
Example 2: Type for which begin/end return pointers
value type of iterators
is double
which is printable by {fmt}
#include <fmt/ranges.h>
class Point4 {
double v_ [4];
public:
explicit
Point4 (double x, double y, double z, double w): v_{x,y,z,w} {}
[[nodiscard]] double x () const noexcept { return v_[0]; }
[[nodiscard]] double y () const noexcept { return v_[1]; }
[[nodiscard]] double z () const noexcept { return v_[2]; }
[[nodiscard]] double w () const noexcept { return v_[3]; }
[[nodiscard]] double const* begin () const noexcept { return v_; }
[[nodiscard]] double const* end () const noexcept { return v_+4; }
};
int main () {
Point4 v {4.7,2.,1.,3.2};
fmt::print("point: {}\n", v);
}
point: [4.7, 2, 1, 3.2]
#include <fmt/color.h>
int main () {
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);
fmt::print(fg(fmt::color::red), s);
fmt::print(fg(fmt::color::green), s);
fmt::print(fg(fmt::color::blue), s);
fmt::print(bg(fmt::color::red), s);
fmt::print(bg(fmt::color::green), s);
fmt::print(bg(fmt::color::blue), s);
fmt::print(fmt::emphasis::bold | bg(fmt::color::red), s);
fmt::print(fmt::emphasis::bold | fmt::emphasis::italic | bg(fmt::color::red), s);
}
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
Only available for numeric types:
int
, float
, double
, bool
, char
, …
Integers
#include <fmt/format.h>
int main () {
int i = 10000000;
fmt::print("{}\n", i);
auto s = fmt::format(
std::locale("en_US.UTF-8"),"{:L}", i);
fmt::print("{}\n", s);
fmt::print("--------------------\n");
std::locale::global(std::locale("en_US.UTF-8"));
fmt::print("{}\n", i);
fmt::print("{:L}\n", i);
}
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
#include <fmt/format.h>
int main () {
double x = 123.45;
fmt::print("{}\n", x);
auto s = fmt::format(
std::locale("de_DE.UTF-8"),"{:L}", x);
fmt::print("{}\n", s);
fmt::print("--------------------\n");
std::locale::global(std::locale("de_DE.UTF-8"));
fmt::print("{}\n", x);
fmt::print("{:L}\n", x);
}
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
Does (as of {fmt} v8) not yet work for floating-point numbers and pointers.
#include <array>
#include <iostream>
#include <fmt/ranges.h>
#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;
}
int main () {
constexpr auto s = compile_time_itoa(37);
// s = {'3','7',' ',' ',' '}
std::cout << s.data() << '\n';
fmt::print("{}\n", s);
}
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.
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>
int main () {
fmt::vprint("{}\n", fmt::make_format_args(47));
fmt::vprint("{} of {}\n", fmt::make_format_args("seven", 9));
}
47
seven of 9
fmt::make_args_checked(str, arguments…)
→
fmt::format_arg_store
- makes a
format_arg_store
that contains references toarguments
- a
format_arg_store
can be implicitly converted toformat_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(@target, format-string, arguments...)
#include <fmt/format.h>
int main ()
{
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();
fmt::print("{}\n", ptrToFormattedData);
fmt::print("{}\n", sizeOfFormattedData);
auto str = to_string(buf); // std::string str = "1.234568e+02";
fmt::print("{}\n", str);
}
#include <fmt/ranges.h>
#include <iterator>
#include <vector>
int main ()
{
double const d = 123.45678;
std::vector<char> vc;
fmt::format_to(std::back_inserter(vc), "{:e}", d);
// vc = {'1','.','2','3','4','5','6','8','e','+','0','2'}
fmt::print("{}\n", vc);
fmt::print("{}\n", vc.size());
}
format_to_n(@target, size, format-string, arguments...)
#include <fmt/format.h>
#include <array>
int main ()
{
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}
fmt::print("{}\n", a.data());
}
formatted_size(format-string, arguments...)
→ size of formatted result
#include <fmt/format.h>
int main ()
{
double const d = 123.45678;
auto size = fmt::formatted_size("{:e}", d); // size = 12
fmt::print("{}", size);
}
- the allocator will be used for the output container only
- formatting functions normally don't do any allocations for built-in and string types
#include <string>
#include <memory>
#include <iostream>
#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";
std::cout << s << '\n';
}
Cheat Sheets
Related …
Official {fmt} Documentation
{fmt}-Related Talks
- A modern formatting library for C++ (Victor Zverovich, 2017)
- {fmt} is Addictive! Using {fmt} and spdlog (C++ Weekly)
- Why does std::format do that? (Charlie Barto, 2021)
Standard Library Formatting C++20
- cppreference:
std::format
- cppreference:
std::vformat
- cppreference:
std::format_to
- cppreference:
std::format_to_n
- cppreference:
std::formatter
- cppreference: Chrono Format Specification
- Quick Introduction to
std::format
(cppstories) - An Extraterrestrial Guide to C++20 Text Formatting (cppstories)
Comments…