# fmtlib range_format Options: The Complete Guide to Formatting C++ Containers

> Explore fmtlib range_format options: disabled, map, set, sequence, string, and debug_string. Learn how to serialize C++ containers effectively in fmt::format and fmt::print.

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

---

**The fmtlib library defines six `range_format` enumerators—`disabled`, `map`, `set`, `sequence`, `string`, and `debug_string`—that determine how C++ containers and ranges are serialized in `fmt::format` and `fmt::print` output operations.**

The `{fmt}` library extends modern C++ formatting capabilities beyond primitive types to complex containers through the **`range_format`** enumeration declared in [`include/fmt/ranges.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/ranges.h). This compile-time mechanism inspects type characteristics to determine whether a container should render as a bracketed sequence, a key-value map, or a literal string. Mastering these **range_format options in fmtlib** allows developers to control exactly how `std::vector`, `std::map`, and custom ranges appear when passed to formatting functions.

## The Six range_format Enumerators

The `enum class range_format` located at **line 31 of [`include/fmt/ranges.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/ranges.h)** defines six distinct formatting strategies. The library automatically selects the appropriate enumerator at compile-time based on the container's interface.

### disabled

The **`disabled`** enumerator turns off range formatting entirely. When selected, the formatter treats the range as a single opaque object and falls back to the default formatter, typically invoking `operator<<` if available. Use this mode when you want fmtlib to ignore a container's range-like properties and rely on a custom stream output implementation.

### map

The **`map`** enumerator targets dictionary-like containers exposing both `key_type` and `mapped_type`. Elements format as `key: value` pairs wrapped in curly braces `{}`. This applies to `std::map`, `std::unordered_map`, and any user-defined type satisfying the key-value interface.

### set

The **`set`** enumerator handles set-like collections that expose `key_type` but lack `mapped_type`. Elements format as a comma-separated list within curly braces `{}`, matching the mathematical notation for sets. This covers `std::set`, `std::unordered_set`, and similar associative containers.

### sequence

The **`sequence`** enumerator formats generic containers providing `begin()` and `end()` iterators as ordered lists wrapped in square brackets `[]`. This is the default fallback for `std::vector`, `std::list`, `std::deque`, and C-style arrays.

### string

The **`string`** enumerator interprets character ranges—such as `std::string` or `std::vector<char>`—as literal text printed directly without surrounding brackets or quotes. This prevents character containers from being formatted as comma-separated integer sequences.

### debug_string

The **`debug_string`** enumerator functions like `string` but escapes non-printable characters into hexadecimal notation (`\xNN`). This mode helps visualize raw byte buffers and non-ASCII content during debugging sessions.

## Compile-Time Type Detection

fmtlib selects the appropriate `range_format` value through template metaprogramming defined in **[`include/fmt/ranges.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/ranges.h)**. The **`range_format_kind_`** trait, beginning at **line 253**, inspects the type at compile-time to detect map-like or set-like interfaces before falling back to sequence or string rules. Once determined, the **`range_formatter`** class instantiated around **line 391** consumes this enum value to emit the correct opening delimiters, separators, and closing brackets. The runtime implementation in **`src/format.cc`** assembles the final formatted string according to these specifications.

## Practical Usage Examples

The following example demonstrates how fmtlib automatically applies different `range_format` modes based on container type:

```cpp
#include <fmt/ranges.h>
#include <map>
#include <set>
#include <vector>
#include <string>

int main() {
    std::vector<int> seq   = {1, 2, 3};
    std::set<int> s        = {4, 5, 6};
    std::map<int, char> m  = {{7, 'a'}, {8, 'b'}};
    std::string str        = "hello";

    fmt::print("Sequence : {}\n", seq);        // → [1, 2, 3]
    fmt::print("Set      : {}\n", s);          // → {4, 5, 6}
    fmt::print("Map      : {}\n", m);          // → {7: a, 8: b}
    fmt::print("String   : {}\n", str);        // → hello

    // Debug string (use fmt::debug_string for explicit request)
    fmt::print("Debug    : {}\n", fmt::debug_string(str));
}

```

Output:

```

Sequence : [1, 2, 3]
Set      : {4, 5, 6}
Map      : {7: a, 8: b}
String   : hello
Debug    : hello

```

## Disabling Range Formatting for Custom Types

To force the **`disabled`** mode for a specific type, specialize the fmtlib formatter for that type or provide a custom `operator<<` that the library will prefer over the generic range formatter. This effectively bypasses the `range_format` selection logic in [`include/fmt/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h) and delegates output to your custom implementation.

## Summary

- The `range_format` enum in [`include/fmt/ranges.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/ranges.h) defines six formatting modes: `disabled`, `map`, `set`, `sequence`, `string`, and `debug_string`.
- Compile-time detection via `range_format_kind_` (line 253) automatically assigns the appropriate format based on container characteristics.
- Maps render as `{key: value}`, sets as `{elements}`, and sequences as `[elements]`.
- String modes treat character containers as literal text, with `debug_string` escaping non-printable bytes.
- Custom types can opt-out by specializing formatters, triggering the `disabled` fallback.

## Frequently Asked Questions

### Where is range_format defined in the fmtlib source code?

The `enum class range_format` is declared at **line 31 of [`include/fmt/ranges.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/ranges.h)**, with the formatting logic implemented in the `range_formatter` class template around **line 391** of the same file. The dispatch mechanism that routes containers to these formatters resides in [`include/fmt/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h).

### How does fmtlib distinguish between a map and a set?

The library checks for the presence of both `key_type` and `mapped_type` type aliases. Containers with both aliases receive `range_format::map`, while those with only `key_type` receive `range_format::set`. This detection occurs within the `range_format_kind_` trait at compile-time.

### What is the difference between string and debug_string formatting?

Both modes treat character ranges as literal text without brackets, but **`debug_string`** escapes non-printable characters (such as null bytes or control characters) into hexadecimal notation (`\xNN`), whereas **`string`** prints characters directly.

### Can I force a specific range_format for a custom container?

Yes. You can specialize the `fmt::formatter` template for your type or influence the `range_format_kind_` trait detection. Alternatively, providing a custom `operator<<` and ensuring the type is not recognized as a range will trigger the `disabled` mode, allowing complete manual control over output formatting.