* Don't let ADL pick to_string_view
02bf4d1c disabled ADL for to_string_view by qualifying the is_string trait,
and has_to_string_view and char_t are qualified for the same reason. Two call
sites were left behind: value's string constructor and the write() overload
for types with a string view conversion. Both sit inside fmt::detail, where an
unqualified call adds the argument's own namespace to the overload set.
That splits the two halves of one decision. Both call sites are reached only
through has_to_string_view or char_t, which are defined by the qualified
expression, so ADL can never be needed to satisfy them - it can only add
candidates the gate never considered. When the argument's namespace declares a
to_string_view template, the two tie during partial ordering and the call is
ambiguous:
core.h(2211): error C2668: 'to_string_view': ambiguous call to overloaded
function
note: could be 'string_view N::to_string_view<T>(const T&)' [found using
argument-dependent lookup]
note: or 'basic_string_view<char> fmt::detail::to_string_view<T,0>(const T&)'
Both are reachable. format("{}", x) stores the argument through value's
constructor; to_string(x) passes it to detail::write unmapped, which lands on
the write() overload, as do FMT_COMPILE named fields and
nested_formatter::write_arg. Reverting either line alone breaks the build of
the test that covers it.
This turned up in Microsoft Office, which declares a constrained
to_string_view template next to its own string types. It only breaks where
those types are distinct classes, so the same code compiles on platforms whose
string types are std aliases - the ADL set is namespace std there and picks up
nothing.
One behaviour change worth noting: a non-template to_string_view in the
argument's namespace used to win outright at these call sites, so a type that
satisfies is_std_string_like via find_first_of and data() but has no size()
formatted through ADL and now fails to compile, because the trait only checks
that the qualified overload is viable, not that its body instantiates. That is
the removed extension point going away rather than a new restriction; ADL
to_string_view stopped being supported in 02bf4d1c.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
||
|---|---|---|
| .github | ||
| doc | ||
| include/fmt | ||
| src | ||
| support | ||
| test | ||
| .clang-format | ||
| .clang-tidy | ||
| .cmake-format | ||
| .gitignore | ||
| ChangeLog.md | ||
| CMakeLists.txt | ||
| CONTRIBUTING.md | ||
| LICENSE | ||
| README.md | ||
{fmt} is an open-source formatting library providing a fast and safe alternative to C stdio and C++ iostreams.
Q&A: ask questions on StackOverflow with the tag fmt.
Try {fmt} in Compiler Explorer.
Features
- Simple format API with positional arguments for localization
- Implementation of C++20 std::format and C++23 std::print
- Format string syntax similar to Python's format
- Fast IEEE 754 floating-point formatter with correct rounding, shortness and round-trip guarantees using the Dragonbox algorithm
- Portable Unicode support
- Safe printf implementation including the POSIX extension for positional arguments
- Extensibility: support for user-defined types
- High performance: faster than common standard library
implementations of
(s)printf, iostreams,to_stringandto_chars, see Speed tests and Converting a hundred million integers to strings per second - Small code size both in terms of source code with the minimum
configuration consisting of just three files,
core.h,format.handformat-inl.h, and compiled code; see Compile time and code bloat - Reliability: the library has an extensive set of tests and is continuously fuzzed
- Safety: the library is fully type-safe, errors in format strings can be reported at compile time, automatic memory management prevents buffer overflow errors
- Ease of use: small self-contained code base, no external dependencies, permissive MIT license
- Portability with consistent output across platforms and support for older compilers
- Clean warning-free codebase even on high warning levels such as
-Wall -Wextra -pedantic - Locale independence by default
- Optional header-only configuration enabled with the
FMT_HEADER_ONLYmacro
See the documentation for more details.
Examples
Print to stdout (run)
#include <fmt/core.h>
int main() {
fmt::print("Hello, world!\n");
}
Format a string (run)
std::string s = fmt::format("The answer is {}.", 42);
// s == "The answer is 42."
Format a string using positional arguments (run)
std::string s = fmt::format("I'd rather be {1} than {0}.", "right", "happy");
// s == "I'd rather be happy than right."
Print dates and times (run)
#include <fmt/chrono.h>
int main() {
auto now = std::chrono::system_clock::now();
fmt::print("Date and time: {}\n", now);
fmt::print("Time: {:%H:%M}\n", now);
}
Output:
Date and time: 2023-12-26 19:10:31.557195597
Time: 19:10
Print a container (run)
#include <vector>
#include <fmt/ranges.h>
int main() {
std::vector<int> v = {1, 2, 3};
fmt::print("{}\n", v);
}
Output:
[1, 2, 3]
Check a format string at compile time
std::string s = fmt::format("{:d}", "I am not a number");
This gives a compile-time error in C++20 because d is an invalid
format specifier for a string.
Write a file from a single thread
#include <fmt/os.h>
int main() {
auto out = fmt::output_file("guide.txt");
out.print("Don't {}", "Panic");
}
This can be up to 9 times faster than fprintf.
Print with colors and text styles
#include <fmt/color.h>
int main() {
fmt::print(fg(fmt::color::crimson) | fmt::emphasis::bold,
"Hello, {}!\n", "world");
fmt::print(fg(fmt::color::floral_white) | bg(fmt::color::slate_gray) |
fmt::emphasis::underline, "Olá, {}!\n", "Mundo");
fmt::print(fg(fmt::color::steel_blue) | fmt::emphasis::italic,
"你好{}!\n", "世界");
}
Output on a modern terminal with Unicode support:
Performance
{fmt} can be tens of percent to 20–30 times faster than sprintf and
iostreams, especially for numeric formatting. It minimizes dynamic memory
allocations and can optionally compile format strings into efficient formatting code.
See format-benchmark and dtoa-benchmark for benchmarks and methodology.
Time per double (smaller is better):
ostringstream and sprintf are omitted because they are an order of
magnitude slower than the other methods.
Compile time and code bloat
The script bloat-test.py from format-benchmark measures the
compile-time and code-size overhead each formatting method adds to application
code. It generates 100 translation units and uses printf or its alternative
five times in each to simulate a medium-sized project. Library and module build
costs are excluded. Results on an Apple M5 Max running macOS 26.6.2 with
Apple Clang 21.0.0 (clang-2100.1.1.101), taking the best of three runs, are
shown in the following tables.
Optimized build (-O3)
| Method | Compile time, s | Binary size, KiB | Stripped size, KiB |
|---|---|---|---|
| printf | 1.6 | 54 | 50 |
| IOStreams | 25.5 | 98 | 84 |
| fmt 12.2 (headers) | 5.1 | 54 | 50 |
| fmt 12.2 (module) | 3.7 | 59 | 50 |
| Boost Format 1.92 | 49.1 | 517 | 317 |
Using modular {fmt} reduces optimized application-code compile time by 27% without changing the reported stripped binary size.
Non-optimized build
| Method | Compile time, s | Binary size, KiB | Stripped size, KiB |
|---|---|---|---|
| printf | 1.6 | 54 | 50 |
| IOStreams | 26.0 | 88 | 68 |
| fmt 12.2 (headers) | 4.9 | 87 | 84 |
| fmt 12.2 (module) | 3.2 | 77 | 68 |
| Boost Format 1.92 | 35.7 | 741 | 431 |
libc, libc++, libfmt, and libfmt-module were linked as shared libraries
to compare formatting function overhead only. Boost Format is header-only.
Projects using {fmt}
Notable users include: