P2286 proposes formatting ranges without handwritten loops
Formatting a range requires decisions about iteration and proxy references as well as punctuation. P2286R0 exposes those constraints while proposing standard formatter support and a joining utility.
Printing the result of a string split should be a small part of investigating string splitting. In C++, it can instead become the task that dominates the experiment. A range adaptor produces a useful sequence, but the standard output interfaces do not automatically know how to present it. Nested ranges require nested traversal, with delimiter handling repeated around the actual question under investigation.
Barry Revzin opens P2286R0, "Formatting Ranges" with that problem. The paper is dated January 14. It proposes standard formatting support for ranges and related types, drawing on existing {fmt} behavior. Its design questions extend beyond choosing brackets because a generic formatter must work with the iteration properties of the object it receives.
I appreciate C++ abstractions that avoid runtime overhead, but their integration costs matter too. A range pipeline that needs a custom traversal just to inspect its result leaves ordinary diagnostic work unnecessarily complicated. The proposal addresses a concrete usability gap between two substantial standard-library facilities.
Standard types need standard support
The earlier C++23 ranges plan identifies printing views as a priority. It notes that range-v3 had printable views while C++20's facilities do not provide equivalent direct printing. The issue is therefore part of integrating the ranges library, rather than merely adding another way to spell an output statement.
P2286 explains why an application cannot solve the entire problem by adding a broad formatter for every standard range. These are not the application's own types. Broad customizations for standard types risk conflicts when larger programs combine libraries. The standard library is in the position to define support consistently for its containers and views.
Pairs and tuples belong in the discussion because ranges can produce structured elements. A formatter for the outer sequence is insufficient if its elements cannot be formatted. The proposal includes pair and tuple when their component types are formattable. It discusses optional and variant too, but assigns them lower importance because their representations are less obvious and they are less directly connected to ranges.
Strings create the opposite problem. A string is a range, but treating it as an arbitrary sequence of characters would discard its existing textual interpretation. A generic range formatter must coexist with more specific formatters. P2286 therefore asks for a clearly specified constraint that lets more specific customizations take precedence.
This also affects user-defined containers. A broad fallback can make them printable, but their authors may need a domain-specific representation. The proposal explicitly considers whether a user can write a more constrained specialization than the library's generic one. Specifying the fallback's constraint is therefore part of preserving customization, rather than an implementation detail that can be left entirely unspecified.
Default formatting and joining solve different problems
The paper proposes both direct formatting and a joining utility. Direct formatting gives an arbitrary formattable range a useful default representation. A joiner gives the caller control over separators and element formatting. Those requirements differ when output is intended for inspection versus a particular textual layout.
P2286 demonstrates the latter with {fmt} and a sequence of byte values. Formatting each element as two hexadecimal digits and joining with colons produces a familiar address-like representation. The important mechanism is that the format specifier applies to the elements while the joiner supplies the separator. The outer formatting operation does not need a handwritten loop.
The proposed standard joining name is provisional. The paper suggests format_join while acknowledging that views::join already exists. A range adaptor that flattens ranges and an output utility that inserts textual separators perform different jobs. Their related vocabulary should not obscure the distinction in behavior.
Punctuation for the default representation remains deliberately unsettled in this revision. Revzin discusses braces and square brackets for ranges and a distinct representation for tuples. He considers having a useful representation more important than prescribing the best punctuation. An account of R0 therefore cannot promise a final standardized output string for every container.
Const access limits which views can be formatted
The draft identifies a constraint in format's argument interface. Taking arguments through const references does not make every view iterable. Some C++20 adaptors, including filter and drop_while, lack const iteration. A generic formatter must address the iteration interface it actually receives.
Converting an argument to a view can handle some cases, as the paper describes from {fmt} experience. It does not solve the case of a move-only view that cannot be iterated through const access. Copying is unavailable, and const iteration is unavailable. Supporting that object directly would require changing the formatting argument interface.
The paper uses the proposed coroutine generator as an example. It suggests a forwarding-reference joiner as the available route for these cases. Collecting the values into a vector is another possible workaround in the discussion, but that introduces materialization just to obtain output. The problem is therefore about access and ownership semantics as much as formatting syntax.
I find this limitation worth making visible. Generic code that takes a const reference often looks maximally permissive. For a lazy range, the operation needed to observe a value may require mutable iteration state. Formatting such a range has to respect that requirement instead of assuming every observation is const.
Proxy references need their own decision
vector<bool> supplies another boundary case. Its value type is bool, but its reference type is a proxy. Knowing that the value type is formattable does not automatically establish that formatting the dereferenced iterator is supported. A range formatter needs a rule for that relationship.
P2286 considers constructing values from references or making the proxy itself formattable. Its proposed direction includes a formatter for vector<bool>::reference and requires the relevant value and reference types to be formattable. That decision connects the generic range rule to the actual type returned by iteration. It also explains why a container-printing proposal must examine iterator semantics before it can offer consistent output for containers whose elements do not expose ordinary references.