-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Enable constexpr support for fmt::format (fmtlib#3403) #4456
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Enable constexpr support for fmt::format (fmtlib#3403) #4456
Conversation
vitaut
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the PR!
include/fmt/base.h
Outdated
| #endif | ||
|
|
||
| // Detect constexpr std::string. | ||
| #if !FMT_USE_CONSTEVAL |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does it depend on consteval?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FMT_USE_CONSTEVAL enables FMT_CONSTEXPR20 which is required.
I could add comment or introduce something FMT_USE_CONSTEXPR20
test/compile-test.cc
Outdated
| constexpr auto result = []() { | ||
| return fmt::format(FMT_COMPILE("{}"), true) == "true"; | ||
| }(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need a lambda here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, unfortunately we do need it. The issue is that all allocated memory at compile time should be deallocated.
That means we are not able to write like this:
constexpr auto s = fmt::format(FMT_COMPILE("{}"), true)); // leaks allocated memory at compile-time to runtime.
EXPECT_EQ("true", s);
Alternatively we could use static_assert:
static_assert(fmt::format(FMT_COMPILE("{}"), true) == "true");
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's keep the lambda for now but I don't think we need to test different arguments since this is already tested elsewhere. What we need to test here is that fmt::format can be called at compile time so I suggest picking on type of an argument (e.g. int) and testing it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have replaced boolean test cases with int and drop test case for a type with user provided formatter.
0363675 to
8468cc5
Compare
8468cc5 to
6a0595d
Compare
6a0595d to
7e7a4e9
Compare
|
Merged, thanks! |
# 12.0.0 - 2025-09-17 - Optimized the default floating point formatting (fmtlib/fmt#3675, fmtlib/fmt#4516). In particular, formatting a `double` with format string compilation into a stack allocated buffer is more than 60% faster in version 12.0 compared to 11.2 according to [dtoa-benchmark](https://github.com/fmtlib/dtoa-benchmark): ``` Function Time (ns) Speedup fmt11 34.471 1.00x fmt12 21.000 1.64x ``` <img width="766" height="609" src="https://github.com/user-attachments/assets/d7d768ad-7543-468c-b0bb-449abf73b31b" /> - Added `constexpr` support to `fmt::format`. For example: ```c++ #include <fmt/compile.h> using namespace fmt::literals; std::string s = fmt::format(""_cf, 42); ``` now works at compile time provided that `std::string` supports `constexpr` (fmtlib/fmt#3403, fmtlib/fmt#4456). Thanks @msvetkin. - Added `FMT_STATIC_FORMAT` that allows formatting into a string of the exact required size at compile time. For example: ```c++ #include <fmt/compile.h> constexpr auto s = FMT_STATIC_FORMAT("{}", 42); ``` compiles to just ```s __ZL1s: .asciiz "42" ``` It can be accessed as a C string with `s.c_str()` or as a string view with `s.str()`. - Improved C++20 module support - Switched to using estimated display width in precision. For example: ```c++ fmt::print("|{:.4}|\n|1234|\n", "🐱🐱🐱"); ``` prints  because `🐱` has an estimated width of 2 - Fix interaction between debug presentation, precision, and width for strings - Implemented allocator propagation on `basic_memory_buffer` move - Fixed an ambiguity between `std::reference_wrapper<T>` and `format_as` formatters - Removed the following deprecated APIs: - `has_formatter`: use `is_formattable` instead, - `basic_format_args::parse_context_type`, `basic_format_args::formatter_type` and similar aliases in context types, - wide stream overload of `fmt::printf`, - wide stream overloads of `fmt::print` that take text styles, - `is_*char` traits, - `fmt::localtime`. - Deprecated wide overloads of `fmt::fprintf` and `fmt::sprintf`. - Improved diagnostics for the incorrect usage of `fmt::ptr` - Made handling of ANSI escape sequences more efficient - Fixed a buffer overflow on all emphasis flags set - Fixed an integer overflow for precision close to the max `int` value. - Fixed compatibility with WASI (fmtlib/fmt#4496, - Fixed `back_insert_iterator` detection, preventing a fallback on slower path that handles arbitrary iterators - Fixed handling of invalid glibc `FILE` buffers - Added `wchar_t` support to the `std::byte` formatter - Changed component prefix from `fmt-` to `fmt_` for compatibility with NSIS/CPack on Windows, e.g. `fmt-doc` changed to `fmt_doc` - Added the `FMT_CUSTOM_ASSERT_FAIL` macro to simplify providing a custom `fmt::assert_fail` implementation - Switched to `FMT_THROW` on reporting format errors so that it can be overriden by users when exceptions are disabled - Improved master project detection and disabled install targets when using {fmt} as a subproject by default - Made various code improvements - Added Conan instructions to the docs - Removed Bazel files to avoid issues with downstream packaging - Added more entries for generated files to `.gitignore` - Fixed various warnings and compilation issues
- Update from version 11.2.0 to 12.1.0
- Update of rootfile
- so-bump so mpd requires shipping
- Changelog
12.1.0
- Optimized `buffer::append`, resulting in up to ~16% improvement on spdlog
benchmarks (fmtlib/fmt#4541). Thanks @fyrsta7.
- Worked around an ABI incompatibility in `std::locale_ref` between clang and
gcc (fmtlib/fmt#4573).
- Made `std::variant` and `std::expected` formatters work with `format_as`
(fmtlib/fmt#4574,
fmtlib/fmt#4575). Thanks @phprus.
- Made `fmt::join<string_view>` work with C++ modules
(fmtlib/fmt#4379,
fmtlib/fmt#4577). Thanks @Arghnews.
- Exported `fmt::is_compiled_string` and `operator""_cf` from the module
(fmtlib/fmt#4544). Thanks @CrackedMatter.
- Fixed a compatibility issue with C++ modules in clang
(fmtlib/fmt#4548). Thanks @tsarn.
- Added support for cv-qualified types to the `std::optional` formatter
(fmtlib/fmt#4561,
fmtlib/fmt#4562). Thanks @OleksandrKvl.
- Added demangling support (used in exception and `std::type_info` formatters)
for libc++ and clang-cl
(fmtlib/fmt#4542,
fmtlib/fmt#4560,
fmtlib/fmt#4568,
fmtlib/fmt#4571).
Thanks @FatihBAKIR and @rohitsutreja.
- Switched to global `malloc`/`free` to enable allocator customization
(fmtlib/fmt#4569,
fmtlib/fmt#4570). Thanks @rohitsutreja.
- Made the `FMT_USE_CONSTEVAL` macro configurable by users
(fmtlib/fmt#4546). Thanks @SnapperTT.
- Fixed compilation with locales disabled in the header-only mode
(fmtlib/fmt#4550).
- Fixed compilation with clang 21 and `-std=c++20`
(fmtlib/fmt#4552).
- Fixed a dynamic linking issue with clang-cl
(fmtlib/fmt#4576,
fmtlib/fmt#4584). Thanks @FatihBAKIR.
- Fixed a warning suppression leakage on gcc
(fmtlib/fmt#4588). Thanks @ZedThree.
- Made more internal color APIs `constexpr`
(fmtlib/fmt#4581). Thanks @ishani.
- Fixed compatibility with clang as a host compiler for NVCC
(fmtlib/fmt#4564). Thanks @valgur.
- Fixed various warnings and lint issues
(fmtlib/fmt#4565,
fmtlib/fmt#4572,
fmtlib/fmt#4557).
Thanks @LiangHuDream and @teruyamato0731.
- Improved documentation
(fmtlib/fmt#4549,
fmtlib/fmt#4551,
fmtlib/fmt#4566,
fmtlib/fmt#4567,
fmtlib/fmt#4578,).
Thanks @teruyamato0731, @petersteneteg and @zimmerman-dev.
12.0.0
- Optimized the default floating point formatting
(fmtlib/fmt#3675,
fmtlib/fmt#4516). In particular, formatting a
`double` with format string compilation into a stack allocated buffer is
more than 60% faster in version 12.0 compared to 11.2 according to
[dtoa-benchmark](https://github.com/fmtlib/dtoa-benchmark):
```
Function Time (ns) Speedup
fmt11 34.471 1.00x
fmt12 21.000 1.64x
```
<img width="766" height="609" src="https://github.com/user-attachments/assets/d7d768ad-7543-468c-b0bb-449abf73b31b" />
- Added `constexpr` support to `fmt::format`. For example:
```c++
#include <fmt/compile.h>
using namespace fmt::literals;
std::string s = fmt::format(""_cf, 42);
```
now works at compile time provided that `std::string` supports `constexpr`
(fmtlib/fmt#3403,
fmtlib/fmt#4456). Thanks @msvetkin.
- Added `FMT_STATIC_FORMAT` that allows formatting into a string of the exact
required size at compile time.
For example:
```c++
#include <fmt/compile.h>
constexpr auto s = FMT_STATIC_FORMAT("{}", 42);
```
compiles to just
```s
__ZL1s:
.asciiz "42"
```
It can be accessed as a C string with `s.c_str()` or as a string view with
`s.str()`.
- Improved C++20 module support
(fmtlib/fmt#4451,
fmtlib/fmt#4459,
fmtlib/fmt#4476,
fmtlib/fmt#4488,
fmtlib/fmt#4491,
fmtlib/fmt#4495).
Thanks @arBmind, @tkhyn, @Mishura4, @anonymouspc and @autoantwort.
- Switched to using estimated display width in precision. For example:
```c++
fmt::print("|{:.4}|\n|1234|\n", "🐱🐱🐱");
```
prints

because `🐱` has an estimated width of 2
(fmtlib/fmt#4272,
fmtlib/fmt#4443,
fmtlib/fmt#4475).
Thanks @nikhilreddydev and @localspook.
- Fix interaction between debug presentation, precision, and width for strings
(fmtlib/fmt#4478). Thanks @localspook.
- Implemented allocator propagation on `basic_memory_buffer` move
(fmtlib/fmt#4487,
fmtlib/fmt#4490). Thanks @toprakmurat.
- Fixed an ambiguity between `std::reference_wrapper<T>` and `format_as`
formatters (fmtlib/fmt#4424,
fmtlib/fmt#4434). Thanks @jeremy-rifkin.
- Removed the following deprecated APIs:
- `has_formatter`: use `is_formattable` instead,
- `basic_format_args::parse_context_type`,
`basic_format_args::formatter_type` and similar aliases in context types,
- wide stream overload of `fmt::printf`,
- wide stream overloads of `fmt::print` that take text styles,
- `is_*char` traits,
- `fmt::localtime`.
- Deprecated wide overloads of `fmt::fprintf` and `fmt::sprintf`.
- Improved diagnostics for the incorrect usage of `fmt::ptr`
(fmtlib/fmt#4453). Thanks @TobiSchluter.
- Made handling of ANSI escape sequences more efficient
(fmtlib/fmt#4511,
fmtlib/fmt#4528).
Thanks @localspook and @Anas-Hamdane.
- Fixed a buffer overflow on all emphasis flags set
(fmtlib/fmt#4498). Thanks @dominicpoeschko.
- Fixed an integer overflow for precision close to the max `int` value.
- Fixed compatibility with WASI (fmtlib/fmt#4496,
fmtlib/fmt#4497). Thanks @whitequark.
- Fixed `back_insert_iterator` detection, preventing a fallback on slower path
that handles arbitrary iterators (fmtlib/fmt#4454).
- Fixed handling of invalid glibc `FILE` buffers
(fmtlib/fmt#4469).
- Added `wchar_t` support to the `std::byte` formatter
(fmtlib/fmt#4479,
fmtlib/fmt#4480). Thanks @phprus.
- Changed component prefix from `fmt-` to `fmt_` for compatibility with
NSIS/CPack on Windows, e.g. `fmt-doc` changed to `fmt_doc`
(fmtlib/fmt#4441,
fmtlib/fmt#4442). Thanks @n-stein.
- Added the `FMT_CUSTOM_ASSERT_FAIL` macro to simplify providing a custom
`fmt::assert_fail` implementation (fmtlib/fmt#4505).
Thanks @HazardyKnusperkeks.
- Switched to `FMT_THROW` on reporting format errors so that it can be
overriden by users when exceptions are disabled
(fmtlib/fmt#4521). Thanks @HazardyKnusperkeks.
- Improved master project detection and disabled install targets when using
{fmt} as a subproject by default (fmtlib/fmt#4536).
Thanks @crueter.
- Made various code improvements
(fmtlib/fmt#4445,
fmtlib/fmt#4448,
fmtlib/fmt#4473,
fmtlib/fmt#4522).
Thanks @localspook, @tchaikov and @way4sahil.
- Added Conan instructions to the docs
(fmtlib/fmt#4537). Thanks @uilianries.
- Removed Bazel files to avoid issues with downstream packaging
(fmtlib/fmt#4530). Thanks @mering.
- Added more entries for generated files to `.gitignore`
(fmtlib/fmt#4355,
fmtlib/fmt#4512).
Thanks @dinomight and @localspook.
- Fixed various warnings and compilation issues
(fmtlib/fmt#4447,
fmtlib/fmt#4470,
fmtlib/fmt#4474,
fmtlib/fmt#4477,
fmtlib/fmt#4471,
fmtlib/fmt#4483,
fmtlib/fmt#4515,
fmtlib/fmt#4533,
fmtlib/fmt#4534).
Thanks @dodomorandi, @localspook, @remyjette, @Tomek-Stolarczyk, @Mishura4,
@mattiasljungstrom and @FatihBAKIR.
Signed-off-by: Adolf Belka <[email protected]>
Signed-off-by: Michael Tremer <[email protected]>
This PR allows to use fmt::format at compile-time by: