P2286R7 refines the contracts behind range formatting
April's range-formatting revision clarifies formatter state and constness. The changes show why reusable formatting support needs more than a choice of brackets and separators.
A range formatter must decide which object it can iterate and which formatter it can call for each element. Those decisions are easy to hide behind a short output example. Barry Revzin's P2286R7, dated April 22, revises the wording that gives range formatting a consistent implementation contract.
The revision history describes the change since P2286R6 simply as wording. Comparing the two documents reveals substantive precision within that description. The proposal adds a common way to select const access, makes formatter-configuration operations constexpr, and states when parsing may replace customized punctuation. It remains a proposal for C++23, not a release announcement for a standard library.
C++ template abstractions can remove runtime work while adding substantial requirements to compilation and diagnosis. That tradeoff shapes my interest in this revision. A formatter intended to work for broad classes of types needs its constraints to describe the actual operations, or a simple diagnostic task can produce a difficult template error.
Constness belongs to more than one object
The paper's formattable concept asks whether a formatter can parse a specification and format a value. The formatting operation is checked on a const formatter. That does not mean every value passed to it must be const. Some views need nonconst iteration, so forcing const access to the range would exclude valid uses.
R7 introduces an exposition-only alias named fmt-maybe-const. It selects const T when that form is formattable, otherwise T. The range specialization uses this selected form when determining its element reference type and when declaring the object accepted by its formatting operation.
That alignment matters. Selecting an element formatter from one reference type while actually iterating another form of the range could leave the specification describing different operations at different stages. The revision brings the chosen range access and the underlying element type into the same wording.
Map and set specializations receive related attention. Their keys require formatting through const access. Map formatting also uses the selected const or nonconst form for the complete map. These constraints address the actual references exposed by the container instead of assuming every component behaves like a mutable standalone object.
Configuring a formatter must survive parsing
The proposed range_formatter exposes operations to set separators and brackets, along with access to its underlying element formatter. R7 makes those configuration operations constexpr and provides both const and nonconst access to the underlying formatter. The debug-format setter likewise becomes explicitly constexpr.
Parsing is not permitted to replace every customized setting unconditionally. The revised wording says the opening bracket, closing bracket, and separator change if and only if the range type or the bracket-suppression option requires it. This protects configuration established through the reusable formatter interface when the selected format specification does not ask to override it.
That is relevant to application-defined formatters. They may delegate most behaviour to the standard range machinery while selecting punctuation that expresses their own type. The configuration API is useful only if its effect has a defined relationship with the subsequent parse operation. Otherwise a formatter can appear customizable but discard its customization during ordinary use.
The same distinction applies to debug formatting of elements. The paper calls the underlying debug-format setter when the range is not in a string presentation, the element formatter supports that operation, and no explicit element specification is present. Supplying an element specification therefore changes which default is applied.
Escaping has an encoding boundary
The proposal gives escaped representations for characters and strings in Unicode encodings. It distinguishes valid scalar values from code units that do not belong to a valid scalar value. R7 clarifies the references to Unicode properties used to decide which values receive escapes.
The non-Unicode case has a separate status. R7 changes its escaped representation from implementation-defined to unspecified. A user should consequently avoid treating that output as a documented interchange encoding. The format is intended to make values useful for debugging and logging, with explicit qualifications about the source encoding.
This is another reason not to confuse formatted inspection with serialization. Quoting a string and escaping some characters makes element boundaries more legible. It does not by itself establish a stable file format with a parser, schema, and cross-encoding guarantees.
The general facility retains exceptions
Ranges whose element reference reduces to the range's own type remain excluded from the generic specialization. The paper uses filesystem::path to explain recursive constraints. Determining the formattability of a path element would otherwise require determining the same formatter while it is still being instantiated.
My preference is for such limits to appear in the constraint, where the implementation can state the unsupported case directly. A broad promise to format every range would conceal a real recursion problem. P2286R7 improves the wording around those boundaries while retaining reusable formatter state, so application types can adopt the common machinery with a specified relationship between configuration, parsing, and element access.