How constexpr String Support Works with FMT_USE_CONSTEXPR_STRING in fmtlib
The FMT_USE_CONSTEXPR_STRING macro enables compile-time std::string operations in {fmt} by annotating functions with constexpr when your compiler supports C++20 constexpr strings and consteval.
The {fmt} library can evaluate format strings entirely at compile time, producing std::string results suitable for constant expressions. This capability is controlled by the FMT_USE_CONSTEXPR_STRING preprocessor macro, which automatically detects compiler support or can be overridden manually. When enabled, functions like fmt::format and fmt::to_string become constexpr, allowing string formatting in static assertions and template parameters.
Detecting constexpr String Capability
The detection logic resides in include/fmt/format.h (lines 23-41). {fmt} determines whether to enable the feature by checking three conditions:
- Compiler support for
consteval– Required for compile-time function evaluation - Library support for constexpr strings – Checks
__cpp_lib_constexpr_string >= 201907L(C++20 feature) - Toolchain compatibility – Handles known issues with specific compiler combinations
// include/fmt/format.h (lines 23-41)
#if !FMT_USE_CONSTEVAL
# define FMT_USE_CONSTEXPR_STRING 0
#elif defined(__cpp_lib_constexpr_string) && \
__cpp_lib_constexpr_string >= 201907L
# if FMT_CLANG_VERSION && FMT_GLIBCXX_RELEASE
// clang + libstdc++ needs GCC 13.3 or newer (see GCC bug 113294)
# if FMT_GLIBCXX_RELEASE < 13
# define FMT_USE_CONSTEXPR_STRING 0
# elif FMT_GLIBCXX_RELEASE == 13 && __GLIBCXX__ < 20240521
# define FMT_USE_CONSTEXPR_STRING 0
# else
# define FMT_USE_CONSTEXPR_STRING 1
# endif
# else
# define FMT_USE_CONSTEXPR_STRING 1
# endif
#else
# define FMT_USE_CONSTEXPR_STRING 0
#endif
The Clang and libstdc++ Edge Case
When compiling with Clang using libstdc++, the code verifies the underlying GCC version is at least 13.3. Earlier versions contain a bug (GCC bug 113294) that prevents proper constexpr string support even when the feature test macro indicates availability. If the library version predates the fix, FMT_USE_CONSTEXPR_STRING is forced to 0 to avoid ill-formed code.
Exposing the Feature Through FMT_CONSTEXPR_STRING
Once detection completes, {fmt} exposes the capability through a public macro defined in include/fmt/format.h (lines 44-48):
#if FMT_USE_CONSTEXPR_STRING
# define FMT_CONSTEXPR_STRING constexpr
#else
# define FMT_CONSTEXPR_STRING
#endif
All functions capable of compile-time evaluation use this macro. When the feature is disabled, FMT_CONSTEXPR_STRING expands to nothing, keeping functions as ordinary runtime functions. When enabled, it injects the constexpr specifier, allowing the compiler to evaluate calls at compile time.
Functions That Become constexpr
Three primary functions gain compile-time capabilities when FMT_USE_CONSTEXPR_STRING is enabled:
fmt::to_string – Defined in include/fmt/format.h (lines 4582-4597) with the signature:
FMT_NODISCARD FMT_CONSTEXPR_STRING auto to_string(T value) -> std::string
This becomes a constexpr function capable of converting arithmetic types to strings during compilation.
Compile-time fmt::format overload – Located in include/fmt/compile.h (lines 479-496):
FMT_INLINE FMT_CONSTEXPR_STRING auto format(const CompiledFormat& cf, ...)
Accepts pre-compiled format strings and processes them entirely at compile time.
Generic fmt::format overload – Also in compile.h:
FMT_INLINE FMT_CONSTEXPR_STRING auto format(const S&, T&&... args)
Enables fmt::format("{}", 42) to be evaluated as a constant expression when arguments are constexpr.
How Compile-Time Formatting Works
When FMT_USE_CONSTEXPR_STRING is set to 1, the following process occurs during compilation:
- Parsing – The format string literal is parsed by
detail::parse_format_stringduring template instantiation - Compilation – The parser produces a
CompiledFormatobject with allconstexprdata members stored in static storage - Evaluation – Calls matching the
CompiledFormatoverload are instantiated asconstexprfunctions, allowing the compiler to execute the formatting logic while generating the object file
If the feature is disabled, identical code paths execute, but the functions remain runtime-only operations.
Configuration and Trade-offs
Enabling and Disabling
You can override automatic detection by defining the macro before including {fmt} headers:
- Force enable:
-DFMT_USE_CONSTEXPR_STRING=1 - Force disable:
-DFMT_USE_CONSTEXPR_STRING=0
Pass these via compiler flags or in a configuration header that includes fmt/format.h.
Performance Implications
Compile-time formatting increases translation unit compile times and potentially binary size because the parser instantiates for each unique format string literal. Projects prioritizing build speed over compile-time validation can disable the feature to maintain smaller binaries faster compilation.
Summary
FMT_USE_CONSTEXPR_STRINGautomatically detects C++20 constexpr string support via__cpp_lib_constexpr_stringandconstevalavailability- The macro accounts for the GCC 13.3+ requirement when using Clang with libstdc++ to avoid bug 113294
FMT_CONSTEXPR_STRINGabstracts the feature, expanding toconstexprwhen enabled or empty when disabled- Key functions (
to_string,formatoverloads) informat.handcompile.huse this macro to enable static assertions and template parameters with formatted strings - Disabling the feature reduces compile times and binary size at the cost of runtime-only formatting
Frequently Asked Questions
What compilers support FMT_USE_CONSTEXPR_STRING?
The feature requires a compiler supporting consteval and a standard library implementing __cpp_lib_constexpr_string >= 201907L. This includes GCC 13.3+ with libstdc++, MSVC 2019 16.10+, and recent Clang versions with a compatible standard library. The automatic detection logic specifically handles the Clang + libstdc++ combination by checking for GCC 13.3 or later to avoid a known constexpr string bug.
How do I force disable constexpr string support?
Define FMT_USE_CONSTEXPR_STRING=0 before including any {fmt} headers, either through compiler flags (-DFMT_USE_CONSTEXPR_STRING=0) or in a global configuration header. This overrides automatic detection and forces all formatting functions to be runtime-only, which can improve compilation times in large codebases.
Does enabling FMT_USE_CONSTEXPR_STRING affect runtime performance?
Runtime performance remains identical when the feature is enabled because the same code paths execute. However, enabling the feature increases compile times and may increase binary size since the format string parser instantiates templates for each unique format string literal encountered during compilation.
Can I use constexpr formatting with dynamic arguments?
No. While FMT_USE_CONSTEXPR_STRING makes the functions constexpr, the actual compile-time evaluation only occurs when all arguments are constant expressions. If any argument is runtime-determined (like a user input variable), the formatting operation falls back to runtime execution even when the macro is enabled.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →