What Is FMT_STRING in {fmt}? Compile-Time Format String Validation Explained

FMT_STRING is a macro supplied by the {fmt} library that converts string literals into compile-time constants, enabling static validation of format specifiers and catching errors like invalid syntax or type mismatches before runtime.

FMT_STRING is a core feature of the {fmt} library (commonly referred to as fmtlib) that enables compile-time parsing of format strings in C++. By wrapping your format string with this macro, you leverage constexpr parsing machinery to detect malformed specifiers during compilation rather than at runtime, providing printf-style safety checks with zero performance overhead.

How FMT_STRING Enables Compile-Time Safety

When you invoke fmt::format with FMT_STRING, the macro performs two critical functions. First, it marks the literal as a compile-time constant, preventing runtime concatenation or dynamic string manipulation. Second, it triggers static validation, parsing the format string at compile time to verify that specifiers match the provided argument types.

In compilers supporting C++14 constexpr string parsing and non-type template parameters, FMT_STRING expands to FMT_STRING_IMPL. On older compilers lacking these capabilities, it falls back to an identity macro that simply returns the literal unchanged, ensuring backward compatibility.

FMT_STRING Implementation Details

The macro definition resides in include/fmt/format.h, where the implementation distinguishes between capable and legacy compilers:

/* When compile-time checks are available */
#define FMT_STRING_IMPL(s, base)                                            \
  using FMT_STRING_VIEW = fmt::detail::ignore_unused(                       \
      FMT_STRING_VIEW(FMT_COMPILE_STRING()));                               \
  s

/* In compilers that cannot perform compile-time checks */
#define FMT_STRING(s) s

/* In capable compilers */
#define FMT_STRING(s) FMT_STRING_IMPL(s, fmt::detail::compile_string)

When full compile-time support is available, FMT_COMPILE_STRING invokes fmt::detail::compile_string_to_view, which converts the literal into a basic_string_view at compile time. This view is then passed to fmt::detail::compile_string (defined in include/fmt/detail/compile.h), a constexpr function that parses the format string and validates specifiers against the argument list.

Static Validation Mechanics

Inside compile_string, the parser builds a compile-time representation of format specifiers. If it encounters illegal specifiers, mismatched braces, or unsupported conversions for the given types, static assertions trigger immediate compilation errors. When parsing succeeds, the macro yields the original literal, which the runtime implementation in src/format.cc uses directly without additional validation overhead.

Practical Usage Examples

Here is how to use FMT_STRING to catch errors at compile time:

#include <fmt/core.h>

int main() {
    int n = 42;

    // ✅ Correct – compile-time validated
    std::string s1 = fmt::format(FMT_STRING("The answer is {}."), n);

    // ❌ Compile-time error: unknown conversion specifier 'q'
    // std::string s2 = fmt::format(FMT_STRING("Bad specifier: {q}"), n);

    // ✅ Using different types – all checked at compile time
    std::string s3 = fmt::format(FMT_STRING("Hex: {:#x}, Float: {:.2f}"), n, 3.14);
}

In the second example, if your compiler supports constexpr parsing, the illegal {q} specifier generates an error during compilation. Without FMT_STRING, this mistake would only surface as a runtime exception or undefined behavior.

Performance Benefits

Using FMT_STRING provides zero runtime overhead. The format string is parsed exactly once during compilation via the machinery in include/fmt/detail/compile.h, and the resulting validation is reused for every call. Unlike runtime-checked formatting, this approach eliminates the cost of parsing the format string on every invocation while maintaining complete type safety.

Summary

  • FMT_STRING is a macro defined in include/fmt/format.h that enables compile-time validation of format strings in the {fmt} library.
  • It expands to FMT_STRING_IMPL on modern compilers, triggering constexpr parsing via compile_string_to_view and compile_string.
  • Static validation catches illegal specifiers, mismatched braces, and type mismatches before code generation, preventing invalid format strings from reaching runtime.
  • On older compilers, the macro falls back to a pass-through identity (#define FMT_STRING(s) s), providing backward compatibility without compile-time checks.
  • The feature adds zero runtime overhead because parsing occurs entirely at compile time in capable environments.

Frequently Asked Questions

What happens if I use FMT_STRING with a non-literal string?

You cannot use FMT_STRING with runtime-generated strings or variables. The macro requires a string literal to enable compile-time parsing through fmt::detail::compile_string. Attempting to pass a std::string or const char* variable results in a compilation error because the macro expects a literal that can be processed by the constexpr machinery.

Does FMT_STRING work with all C++ standards?

FMT_STRING works with all C++ standards, but compile-time validation requires support for C++14 constexpr string parsing and non-type template parameters. On compilers lacking these features, FMT_STRING degrades gracefully to a simple pass-through macro that returns the string literal without static checking, maintaining source compatibility while sacrificing compile-time safety.

Where is the compile-time parsing logic implemented?

The core parsing logic resides in include/fmt/detail/compile.h via the compile_string function, with entry points and macro definitions in include/fmt/format.h. The compile_string_to_view utility in format.h converts literals into basic_string_view instances that the constexpr parser consumes to validate format specifiers against argument types at compile time.

Can I disable FMT_STRING compile-time checking?

You cannot selectively disable the compile-time checks on supported compilers without modifying the source, but you can simply omit the macro to use runtime validation only. If you wrap your format string with FMT_STRING, the library enforces static validation through FMT_COMPILE_STRING; if you pass a bare string literal to fmt::format, it relies on runtime checks implemented in src/format.cc.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →