# How fmt::formatter<T>::parse Works: A Deep Dive into {fmt} Format Specification Parsing

> Explore how fmt::formatter<T>::parse works, dissecting format specification parsing in the fmtlib/fmt library. Understand alignment, width, and precision flag handling.

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

---

**The `fmt::formatter<T>::parse` method scans the format specification between braces (such as `{:>10.2f}`), populates a `format_specs` structure with alignment, width, precision, and type flags, and returns an iterator positioned at the closing brace—all while delegating to specialized parser helpers in [`include/fmt/core.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/core.h) and [`include/fmt/detail/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/detail/format.h).**

The `{fmt}` library (hosted at `fmtlib/fmt`) provides a type‑safe, extensible alternative to `printf` through the `fmt::formatter<T>` template. Every printable type must specialize this template and implement two members: `parse` to interpret the format string and `format` to render the value. Understanding how `parse` consumes the specification substring is essential for customizing output behavior and diagnosing format errors.

## The Two‑Phase Formatter Protocol

Every `fmt::formatter<T>` specialization must satisfy a strict two‑phase contract. First, **`parse`** analyzes the substring between the colon and closing brace in a replacement field. Second, **`format`** uses that metadata to convert the actual value into text. This separation enables compile‑time parsing of literal strings while deferring expensive value conversion to runtime.

## Step‑by‑Step Anatomy of `parse`

The `parse` function accepts a **`format_parse_context&`** and returns an iterator marking the end of the specification. Its implementation follows a predictable pipeline defined in [`include/fmt/core.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/core.h) (starting around line 641).

### 1. Initialize the Specification Storage

`parse` begins by default‑constructing a `fmt::detail::format_specs<Char>` object. This internal struct caches every modifier discovered during scanning, including fill character, alignment, sign rules, width, precision, and type specifier.

### 2. Iterate Over the Format String

The method obtains iterators via `ctx.begin()` and `ctx.end()`. It walks the range until it encounters a closing `}` or reaches the end of the context. This loop examines each character to decide which parsing helper to invoke next.

### 3. Dispatch to Specialized Parsers

Rather than parsing inline, `parse` delegates to dedicated utilities located in [`include/fmt/detail/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/detail/format.h). These helpers include **`parse_align`**, **`parse_sign`**, **`parse_width`**, **`parse_precision`**, and **`parse_type`**. Each function updates the `format_specs` object and returns the new iterator position.

```cpp
constexpr auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
    auto it = ctx.begin();
    auto end = ctx.end();
    it = fmt::detail::parse_align(it, end, specs_);
    it = fmt::detail::parse_sign(it, end, specs_);
    it = fmt::detail::parse_width(it, end, specs_, ctx);
    it = fmt::detail::parse_precision(it, end, specs_, ctx);
    it = fmt::detail::parse_type(it, end, specs_);
    return it;  // points to '}' or end
}

```

### 4. Validate and Error Out

If an unexpected character appears—such as an invalid type specifier—the parser throws **`fmt::format_error`**. This exception propagates immediately, preventing malformed format strings from producing undefined behavior or silent failures.

### 5. Return the Final Position

Upon reaching the closing brace, `parse` returns the iterator positioned at that brace. The `format` function later consumes the stored `format_specs` to drive output generation, ensuring the parsed options precisely control formatting.

## Source Code Locations and Architecture

The generic template resides in **[`include/fmt/core.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/core.h)** around line 641. Specializations for fundamental types and the high‑level dispatch logic live in **[`include/fmt/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h)** (lines 4195‑4227). Low‑level parsing implementations are found in **[`include/fmt/detail/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/detail/format.h)**, while optimized integer and floating‑point formatting algorithms reside in **[`include/fmt/format-inl.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format-inl.h)**.

## Practical Examples

### Built‑in Integer Formatting

When you invoke `fmt::print("{:0>+5}", 42)`, the library instantiates `formatter<int>`. Its `parse` method extracts `0` (fill), `>` (align right), `+` (force sign), and `5` (width), storing these in the internal `specs_` member. The `format` method then applies them to produce `+0042`.

```cpp
#include <fmt/core.h>

int main() {
    // Width = 5, fill = '0', alignment = right, sign = always
    fmt::print("{:0>+5}\n", 42);   // prints "+0042"
}

```

### Custom Point Structure

Specializing `formatter<Point>` requires implementing `parse` to handle custom syntax. You can reuse `fmt::detail::parse_nonnegative_int` to consume dynamic width arguments, storing the result in a member variable for later use in `format`.

```cpp
#include <fmt/core.h>

struct Point { int x, y; };

template <>
struct fmt::formatter<Point> {
    int width = 0;

    constexpr auto parse(fmt::format_parse_context& ctx) -> decltype(ctx.begin()) {
        auto it = ctx.begin();
        if (it != ctx.end() && *it == '}') return it;  // no spec
        width = fmt::detail::parse_nonnegative_int(it, ctx.end(), -1);
        return it;
    }

    template <typename FormatContext>
    auto format(const Point& p, FormatContext& ctx) const -> decltype(ctx.out()) {
        return fmt::format_to(ctx.out(), "({},{})", p.x, p.y);
    }
};

```

### Extending Standard Behavior

You can wrap the default parser by calling `fmt::detail::parse_format_specs`, then inspect remaining characters for custom flags. This lets you add non‑standard modifiers while retaining full compatibility with width and precision controls.

```cpp
template <>
struct fmt::formatter<double> {
    fmt::detail::format_specs<char> specs;
    bool scientific = false;

    constexpr auto parse(fmt::format_parse_context& ctx) -> decltype(ctx.begin()) {
        auto it = ctx.begin();
        it = fmt::detail::parse_format_specs(it, ctx.end(), specs, ctx);
        if (it != ctx.end() && *it == 's') { scientific = true; ++it; }
        return it;
    }

    template <typename FormatContext>
    auto format(const double& val, FormatContext& ctx) const -> decltype(ctx.out()) {
        return scientific ? fmt::format_to(ctx.out(), "{:e}", val)
                          : fmt::format_to(ctx.out(), "{}", val);
    }
};

```

## Summary

- `parse` is a **`constexpr`** member function that consumes the format specification between `{` and `}`.
- It populates a **`format_specs`** struct via helpers such as `parse_align` and `parse_width` defined in [`include/fmt/detail/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/detail/format.h).
- Errors raise **`fmt::format_error`** immediately upon encountering invalid syntax.
- The method returns an iterator positioned at the closing brace, signaling the end of the specification.
- Parsed data persists in the formatter object, guiding the subsequent **`format`** call to produce correctly aligned and padded output.

## Frequently Asked Questions

### What happens if `parse` encounters an invalid format specifier?

The function throws **`fmt::format_error`** with a message indicating the position and nature of the syntax error. This aborts formatting before any output is generated, ensuring type safety.

### Can `fmt::formatter<T>::parse` be evaluated at compile time?

Yes. Because `parse` is marked **`constexpr`** and operates on string literals, compilers can execute it during compilation. This allows the library to catch malformed format strings at build time when using `FMT_STRING` or compile‑time API.

### How does `parse` handle dynamic width or precision?

When the iterator encounters `*` instead of a digit, `parse` invokes **`ctx.next_arg()`** to retrieve the next format argument. It stores that value in the `width` or `precision` field of the `format_specs` structure, enabling runtime‑sized fields like `fmt::format("{:*}", width, value)`.

### Do I need to implement `parse` for every custom type?

Only if you want to support format specifications beyond the default `{}`. For simple placeholder replacement, you can inherit from **`fmt::ostream_formatter`** or provide a trivial `parse` that simply returns `ctx.begin()` without consuming any characters.