# How constexpr String Support Works with FMT_USE_CONSTEXPR_STRING in fmtlib

> Explore how FMT_USE_CONSTEXPR_STRING enables compile-time std::string operations in fmtlib. Learn about C++20 constexpr strings and consteval for efficient string formatting.

- Repository: [Hello World Foundation/fmt](https://github.com/fmtlib/fmt)
- Tags: internals
- Published: 2026-09-05

---

**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`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h)** (lines 23-41). {fmt} determines whether to enable the feature by checking three conditions:

1. **Compiler support for `consteval`** – Required for compile-time function evaluation
2. **Library support for constexpr strings** – Checks `__cpp_lib_constexpr_string >= 201907L` (C++20 feature)
3. **Toolchain compatibility** – Handles known issues with specific compiler combinations

```cpp
// 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](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=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`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h)** (lines 44-48):

```cpp
#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`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h)** (lines 4582-4597) with the signature:

```cpp
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`](https://github.com/fmtlib/fmt/blob/main/include/fmt/compile.h)** (lines 479-496):

```cpp
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`](https://github.com/fmtlib/fmt/blob/main/compile.h):

```cpp
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:

1. **Parsing** – The format string literal is parsed by `detail::parse_format_string` during template instantiation
2. **Compilation** – The parser produces a `CompiledFormat` object with all `constexpr` data members stored in static storage
3. **Evaluation** – Calls matching the `CompiledFormat` overload are instantiated as `constexpr` functions, 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`](https://github.com/fmtlib/fmt/blob/main/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_STRING`** automatically detects C++20 constexpr string support via `__cpp_lib_constexpr_string` and `consteval` availability
- The macro accounts for the **GCC 13.3+ requirement** when using Clang with libstdc++ to avoid bug 113294
- **`FMT_CONSTEXPR_STRING`** abstracts the feature, expanding to `constexpr` when enabled or empty when disabled
- **Key functions** (`to_string`, `format` overloads) in [`format.h`](https://github.com/fmtlib/fmt/blob/main/format.h) and [`compile.h`](https://github.com/fmtlib/fmt/blob/main/compile.h) use 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.