P2286R6 gives C++ ranges a useful formatted representation
Range formatting needs consistent representations and element-level customization. The January revision of P2286 turns those choices into library wording while retaining support for views that cannot be iterated through const.
Barry Revzin's range-formatting proposal begins with a practical obstacle to investigating another library question. He wanted to compare how languages split a string when delimiters occur at its ends. In C++, displaying the resulting range required nested iteration and explicit delimiter handling. P2286R6, dated January 19, proposes formatting support that makes that sort of inspection an ordinary library operation.
The paper targets C++23 but remains a proposal. It supplies wording for ranges, pairs, and tuples, with supporting concepts and formatter interfaces. Its purpose extends beyond one container type. A useful formatter must handle composed ranges whose elements may themselves be ranges, and it must specify what output those compositions produce.
I find the zero-overhead argument for C++ persuasive in many cases, but its library abstractions can demand considerable effort to inspect. A standard way to display a range helps explain what an abstraction does without requiring application-specific output loops. That is useful when the types involved come from the standard library and applications cannot safely add broad customizations for them.
Representation is part of the interface
P2286R6 proposes square brackets for ordinary ranges and parentheses for pairs and tuples. Associative containers receive representations that convey their meaning, with braces for sets and key-value associations for maps. These choices are deliberate output rules, not implementation-defined decoration.
The preceding R5 revision and the R6 revision history explain that the original idea of implementation-defined formatting received objections. Consistent representation matters because users need output they can interpret across implementations. A default that produces some text is less useful if the punctuation and nesting change with the library vendor.
Characters and strings require a related choice. Formatting a string on its own ordinarily produces its contents. Within a range, raw contents can make element boundaries ambiguous. A comma inside a string can look like a separator, and a newline can split one logical value across lines. The proposal therefore uses quoted and escaped representations by default inside ranges and tuples.
The debug format specifier ? exposes that quoted form directly for characters and strings. A formatter can also support a set_debug_format member, allowing an enclosing formatter to select the representation. That creates a mechanism for the default nested behaviour instead of requiring every container formatter to know every string type's implementation.
Range formatting and element formatting are separate
The proposal distinguishes specifiers for the range itself from specifiers for its elements. Applying width to the complete output is different from applying width to each element. Nested formatting consequently needs a way to pass a specification to the formatter at the next level.
This illustrative use follows the proposed formatting model. It requires a library implementing the proposal and is not a claim about existing C++20 support.
#include <format>
#include <vector>
std::string describe_values()
{
std::vector<int> values{10, 15};
return std::format("{::#x}", values);
}
Here the element specification requests hexadecimal values with a base prefix. The range retains its surrounding representation. This separation is what lets the same range formatter support a different numeric presentation without changing the range's element type or adding a bespoke output function.
P2286R6 also records reductions in scope. Earlier individual-element formatting for pairs and tuples was removed because it became complicated and difficult to read. A delimiter-changing format specifier was removed as well. The revision concentrates on a common useful facility while leaving some specialized presentations to custom code.
Formattability depends on the actual reference type
A range formatter needs to determine whether its elements can be formatted. The paper proposes a formattable concept that expresses the existing formatter requirements in code. This allows a generic formatter to participate only when the necessary element operations are available.
Constness creates a subtle distinction. Some views cannot be iterated through a const object, so the test cannot simply force every input to const. The paper explicitly allows formattable<T, char> and formattable<const T, char> to differ. It separately requires the formatter's formatting operation to be callable through a const formatter object.
Those are different constness requirements on different objects. The formatter can retain stable parsed settings while the range needs mutable access for iteration. Confusing them would exclude useful views even though their elements have appropriate formatting support.
A self-referential range creates another constraint problem. The paper uses filesystem::path as an example because iterating it produces path elements. Recursively asking whether an element is formattable can return to the same incomplete formatter specialization. P2286R6 proposes rejecting ranges whose element reference reduces to the range's own type, avoiding that recursion.
Generic support still has deliberate limits
The paper discusses optional and variant types but gives them lower priority than range-related pairs and tuples. Their representation is less obvious, and they are less directly connected to the range work. This matters when interpreting the proposal's ambition. Making ranges formattable does not establish a universal diagnostic representation for every standard type.
My preference is for the generic mechanism to expose enough control for application types without turning the default syntax into another language to learn. P2286R6's reduction of delimiter and tuple-element customization reflects that pressure. The resulting proposal still handles nested ranges through compositional formatters, with explicit constraints for const iteration and element support.