[format.range] # 28 Text processing library [[text]](./#text) ## 28.5 Formatting [[format]](format#range) ### 28.5.7 Formatting of ranges [format.range] #### [28.5.7.1](#fmtkind) Variable template format_kind [[format.range.fmtkind]](format.range.fmtkind) [🔗](#lib:format_kind) `template requires [same_as](concept.same#concept:same_as "18.4.2 Concept same_­as [concept.same]")> constexpr range_format format_kind = see below; ` [1](#fmtkind-1) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7841) A program that instantiates the primary template of format_kind is ill-formed[.](#fmtkind-1.sentence-1) [2](#fmtkind-2) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7845) For a type R, format_kind is defined as follows: - [(2.1)](#fmtkind-2.1) If [same_as](concept.same#concept:same_as "18.4.2 Concept same_­as [concept.same]")>, R> is true,format_kind is range_format​::​disabled[.](#fmtkind-2.1.sentence-1) [*Note [1](#fmtkind-note-1)*: This prevents constraint recursion for ranges whose reference type is the same range type[.](#fmtkind-2.1.sentence-2) For example,std​::​filesystem​::​path is a range of std​::​filesystem​::​path[.](#fmtkind-2.1.sentence-3) — *end note*] - [(2.2)](#fmtkind-2.2) Otherwise, if the [*qualified-id*](expr.prim.id.qual#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]") R​::​key_type is valid and denotes a type: * [(2.2.1)](#fmtkind-2.2.1) If the [*qualified-id*](expr.prim.id.qual#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]") R​::​mapped_type is valid and denotes a type, let U be remove_cvref_t>[.](#fmtkind-2.2.1.sentence-1) If either U is a specialization of pair orU is a specialization of tuple andtuple_size_v == 2,format_kind is range_format​::​map[.](#fmtkind-2.2.1.sentence-2) * [(2.2.2)](#fmtkind-2.2.2) Otherwise, format_kind is range_format​::​set[.](#fmtkind-2.2.2.sentence-1) - [(2.3)](#fmtkind-2.3) Otherwise, format_kind is range_format​::​sequence[.](#fmtkind-2.3.sentence-1) [3](#fmtkind-3) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7879) *Remarks*: Pursuant to [[namespace.std]](namespace.std "16.4.5.2.1 Namespace std"), users may specialize format_kind for cv-unqualified program-defined types that model ranges​::​[input_range](range.refinements#concept:input_range "25.4.6 Other range refinements [range.refinements]")[.](#fmtkind-3.sentence-1) Such specializations shall be usable in constant expressions ([[expr.const]](expr.const "7.7 Constant expressions")) and have type const range_format[.](#fmtkind-3.sentence-2) #### [28.5.7.2](#formatter) Class template range_formatter [[format.range.formatter]](format.range.formatter) [🔗](#lib:range_formatter) namespace std {templaterequires [same_as](concept.same#concept:same_as "18.4.2 Concept same_­as [concept.same]"), T> && [formattable](format.formattable#concept:formattable "28.5.6.3 Concept formattable [format.formattable]")class range_formatter { formatter *underlying_*; // *exposition only* basic_string_view *separator_* = *STATICALLY-WIDEN*(", "); // *exposition only* basic_string_view *opening-bracket_* = *STATICALLY-WIDEN*("["); // *exposition only* basic_string_view *closing-bracket_* = *STATICALLY-WIDEN*("]"); // *exposition only*public:constexpr void set_separator(basic_string_view sep) noexcept; constexpr void set_brackets(basic_string_view opening, basic_string_view closing) noexcept; constexpr formatter& underlying() noexcept { return *underlying_*; }constexpr const formatter& underlying() const noexcept { return *underlying_*; }templateconstexpr typename ParseContext::iterator parse(ParseContext& ctx); templaterequires [formattable](format.formattable#concept:formattable "28.5.6.3 Concept formattable [format.formattable]"), charT> &&[same_as](concept.same#concept:same_as "18.4.2 Concept same_­as [concept.same]")>, T>typename FormatContext::iterator format(R&& r, FormatContext& ctx) const; };} [1](#formatter-1) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7921) The class template range_formatter is a utility for implementing formatter specializations for range types[.](#formatter-1.sentence-1) [2](#formatter-2) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7925) range_formatter interprets *format-spec* as a *range-format-spec*[.](#formatter-2.sentence-1) The syntax of format specifications is as follows: range-format-spec : range-fill-and-alignopt widthopt nopt range-typeopt range-underlying-specopt range-fill-and-align : range-fillopt align range-fill : any character other than { or } or : range-type : m s ?s range-underlying-spec : : format-spec [3](#formatter-3) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7957) For range_formatter, the *format-spec* in a *range-underlying-spec*, if any, is interpreted by formatter[.](#formatter-3.sentence-1) [4](#formatter-4) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7963) The *range-fill-and-align* is interpreted the same way as a *fill-and-align* ([[format.string.std]](format.string.std "28.5.2.2 Standard format specifiers"))[.](#formatter-4.sentence-1) The productions *align* and *width* are described in [[format.string]](format.string "28.5.2 Format string")[.](#formatter-4.sentence-2) [5](#formatter-5) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7969) The n option causes the range to be formatted without the opening and closing brackets[.](#formatter-5.sentence-1) [*Note [1](#formatter-note-1)*: This is equivalent to invoking set_brackets({}, {})[.](#formatter-5.sentence-2) — *end note*] [6](#formatter-6) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7976) The *range-type* specifier changes the way a range is formatted, with certain options only valid with certain argument types[.](#formatter-6.sentence-1) The meaning of the various type options is as specified in Table [115](#tab:formatter.range.type "Table 115: Meaning of range-type options")[.](#formatter-6.sentence-2) Table [115](#tab:formatter.range.type) — Meaning of *range-type* options [[tab:formatter.range.type]](./tab:formatter.range.type) | [🔗](#tab:formatter.range.type-row-1)
**Option** | **Requirements** | **Meaning** | | --- | --- | --- | | [🔗](#tab:formatter.range.type-row-2)
m | T shall be either a specialization of pair or a specialization of tuple such that tuple_size_v is 2[.](#tab:formatter.range.type-row-2-column-2-sentence-1) | Indicates that the opening bracket should be "{", the closing bracket should be "}", the separator should be ", ", and each range element should be formatted as if m were specified for its *tuple-type*[.](#tab:formatter.range.type-row-2-column-3-sentence-1)
[*Note [2](#tab:formatter.range.type-row-2-column-3-note-2)*:
If the n option is provided in addition to the m option, both the opening and closing brackets are still empty[.](#tab:formatter.range.type-row-2-column-3-sentence-2) — *end note*] | | [🔗](#tab:formatter.range.type-row-3)
s | T shall be charT[.](#tab:formatter.range.type-row-3-column-2-sentence-1) | Indicates that the range should be formatted as a string[.](#tab:formatter.range.type-row-3-column-3-sentence-1) | | [🔗](#tab:formatter.range.type-row-4)
?s | T shall be charT[.](#tab:formatter.range.type-row-4-column-2-sentence-1) | Indicates that the range should be formatted as an escaped string ([[format.string.escaped]](format.string.escaped "28.5.6.5 Formatting escaped characters and strings"))[.](#tab:formatter.range.type-row-4-column-3-sentence-1) | If the *range-type* is s or ?s, then there shall be no n option and no *range-underlying-spec*[.](#formatter-6.sentence-3) [🔗](#lib:set_separator,range_formatter) `constexpr void set_separator(basic_string_view sep) noexcept; ` [7](#formatter-7) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8025) *Effects*: Equivalent to: *separator_* = sep; [🔗](#lib:set_brackets,range_formatter) `constexpr void set_brackets(basic_string_view opening, basic_string_view closing) noexcept; ` [8](#formatter-8) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8037) *Effects*: Equivalent to:*opening-bracket_* = opening;*closing-bracket_* = closing; [🔗](#lib:parse,range_formatter) `template constexpr typename ParseContext::iterator parse(ParseContext& ctx); ` [9](#formatter-9) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8054) *Effects*: Parses the format specifiers as a *range-format-spec* and stores the parsed specifiers in *this[.](#formatter-9.sentence-1) Calls *underlying_*.parse(ctx) to parse*format-spec* in *range-format-spec* or, if the latter is not present, an empty *format-spec*[.](#formatter-9.sentence-2) The values of*opening-bracket_*, *closing-bracket_*, and *separator_* are modified if and only if required by the *range-type* or the n option, if present[.](#formatter-9.sentence-3) If: - [(9.1)](#formatter-9.1) the *range-type* is neither s nor ?s, - [(9.2)](#formatter-9.2) *underlying_*.set_debug_format() is a valid expression, and - [(9.3)](#formatter-9.3) there is no *range-underlying-spec*, then calls *underlying_*.set_debug_format()[.](#formatter-9.sentence-4) [10](#formatter-10) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8076) *Returns*: An iterator past the end of the *range-format-spec*[.](#formatter-10.sentence-1) [🔗](#lib:format,range_formatter) `template requires [formattable](format.formattable#concept:formattable "28.5.6.3 Concept formattable [format.formattable]"), charT> && [same_as](concept.same#concept:same_as "18.4.2 Concept same_­as [concept.same]")>, T> typename FormatContext::iterator format(R&& r, FormatContext& ctx) const; ` [11](#formatter-11) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8091) *Effects*: Writes the following into ctx.out(), adjusted according to the *range-format-spec*: - [(11.1)](#formatter-11.1) If the *range-type* was s, then as if by formatting basic_string(from_range, r)[.](#formatter-11.1.sentence-1) - [(11.2)](#formatter-11.2) Otherwise, if the *range-type* was ?s, then as if by formatting basic_string(from_range, r) as an escaped string ([[format.string.escaped]](format.string.escaped "28.5.6.5 Formatting escaped characters and strings"))[.](#formatter-11.2.sentence-1) - [(11.3)](#formatter-11.3) Otherwise, * [(11.3.1)](#formatter-11.3.1) *opening-bracket_*, * [(11.3.2)](#formatter-11.3.2) for each element e of the range r: + [(11.3.2.1)](#formatter-11.3.2.1) the result of writing e via *underlying_* and + [(11.3.2.2)](#formatter-11.3.2.2) *separator_*, unless e is the last element of r, and * [(11.3.3)](#formatter-11.3.3) *closing-bracket_*[.](#formatter-11.3.sentence-1) [12](#formatter-12) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8122) *Returns*: An iterator past the end of the output range[.](#formatter-12.sentence-1) #### [28.5.7.3](#fmtdef) Class template *range-default-formatter* [[format.range.fmtdef]](format.range.fmtdef) [🔗](#lib:range-default-formatter) namespace std {templatestruct *range-default-formatter* { // *exposition only*private:using *maybe-const-r* = *fmt-maybe-const*; // *exposition only* range_formatter>, charT> *underlying_*; // *exposition only*public:constexpr void set_separator(basic_string_view sep) noexcept; constexpr void set_brackets(basic_string_view opening, basic_string_view closing) noexcept; templateconstexpr typename ParseContext::iterator parse(ParseContext& ctx); templatetypename FormatContext::iterator format(*maybe-const-r*& elems, FormatContext& ctx) const; };} [🔗](#lib:set_separator,range-default-formatter) `constexpr void set_separator(basic_string_view sep) noexcept; ` [1](#fmtdef-1) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8161) *Effects*: Equivalent to: *underlying_*.set_separator(sep); [🔗](#lib:set_brackets,range-default-formatter) `constexpr void set_brackets(basic_string_view opening, basic_string_view closing) noexcept; ` [2](#fmtdef-2) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8173) *Effects*: Equivalent to: *underlying_*.set_brackets(opening, closing); [🔗](#lib:parse,range-default-formatter) `template constexpr typename ParseContext::iterator parse(ParseContext& ctx); ` [3](#fmtdef-3) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8186) *Effects*: Equivalent to: return *underlying_*.parse(ctx); [🔗](#lib:format,range-default-formatter) `template typename FormatContext::iterator format(maybe-const-r& elems, FormatContext& ctx) const; ` [4](#fmtdef-4) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8199) *Effects*: Equivalent to: return *underlying_*.format(elems, ctx); #### [28.5.7.4](#fmtmap) Specialization of *range-default-formatter* for maps [[format.range.fmtmap]](format.range.fmtmap) [🔗](#lib:range-default-formatter_) namespace std {templatestruct *range-default-formatter* {private:using *maybe-const-map* = *fmt-maybe-const*; // *exposition only*using *element-type* = // *exposition only* remove_cvref_t>; range_formatter<*element-type*, charT> *underlying_*; // *exposition only*public:constexpr *range-default-formatter*(); templateconstexpr typename ParseContext::iterator parse(ParseContext& ctx); templatetypename FormatContext::iterator format(*maybe-const-map*& r, FormatContext& ctx) const; };} [🔗](#lib:range-default-formatter,constructor) `constexpr range-default-formatter(); ` [1](#fmtmap-1) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8237) *Mandates*: Either: - [(1.1)](#fmtmap-1.1) *element-type* is a specialization of pair, or - [(1.2)](#fmtmap-1.2) *element-type* is a specialization of tuple andtuple_size_v<*element-type*> == 2[.](#fmtmap-1.sentence-1) [2](#fmtmap-2) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8248) *Effects*: Equivalent to:*underlying_*.set_brackets(*STATICALLY-WIDEN*("{"), *STATICALLY-WIDEN*("}"));*underlying_*.underlying().set_brackets({}, {});*underlying_*.underlying().set_separator(*STATICALLY-WIDEN*(": ")); [🔗](#lib:parse,range-default-formatter_) `template constexpr typename ParseContext::iterator parse(ParseContext& ctx); ` [3](#fmtmap-3) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8266) *Effects*: Equivalent to: return *underlying_*.parse(ctx); [🔗](#lib:format,range-default-formatter_) `template typename FormatContext::iterator format(maybe-const-map& r, FormatContext& ctx) const; ` [4](#fmtmap-4) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8279) *Effects*: Equivalent to: return *underlying_*.format(r, ctx); #### [28.5.7.5](#fmtset) Specialization of *range-default-formatter* for sets [[format.range.fmtset]](format.range.fmtset) [🔗](#lib:range-default-formatter__) namespace std {templatestruct *range-default-formatter* {private:using *maybe-const-set* = *fmt-maybe-const*; // *exposition only* range_formatter>, charT> *underlying_*; // *exposition only*public:constexpr *range-default-formatter*(); templateconstexpr typename ParseContext::iterator parse(ParseContext& ctx); templatetypename FormatContext::iterator format(*maybe-const-set*& r, FormatContext& ctx) const; };} [🔗](#lib:range-default-formatter,constructor_) `constexpr range-default-formatter(); ` [1](#fmtset-1) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8316) *Effects*: Equivalent to:*underlying_*.set_brackets(*STATICALLY-WIDEN*("{"), *STATICALLY-WIDEN*("}")); [🔗](#lib:parse,range-default-formatter__) `template constexpr typename ParseContext::iterator parse(ParseContext& ctx); ` [2](#fmtset-2) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8332) *Effects*: Equivalent to: return *underlying_*.parse(ctx); [🔗](#lib:format,range-default-formatter__) `template typename FormatContext::iterator format(maybe-const-set& r, FormatContext& ctx) const; ` [3](#fmtset-3) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8345) *Effects*: Equivalent to: return *underlying_*.format(r, ctx); #### [28.5.7.6](#fmtstr) Specialization of *range-default-formatter* for strings [[format.range.fmtstr]](format.range.fmtstr) [🔗](#lib:range-default-formatter___) namespace std {templaterequires (K == range_format::string || K == range_format::debug_string)struct *range-default-formatter* {private: formatter, charT> *underlying_*; // *exposition only*public:templateconstexpr typename ParseContext::iterator parse(ParseContext& ctx); templatetypename FormatContext::iterator format(*see below*& str, FormatContext& ctx) const; };} [1](#fmtstr-1) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8373) *Mandates*: [same_as](concept.same#concept:same_as "18.4.2 Concept same_­as [concept.same]")>, charT> is true[.](#fmtstr-1.sentence-1) [🔗](#lib:parse,range-default-formatter___) `template constexpr typename ParseContext::iterator parse(ParseContext& ctx); ` [2](#fmtstr-2) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8386) *Effects*: Equivalent to:auto i = *underlying_*.parse(ctx);if constexpr (K == range_format::debug_string) {*underlying_*.set_debug_format();}return i; [🔗](#lib:format,range-default-formatter___) `template typename FormatContext::iterator format(see below& r, FormatContext& ctx) const; ` [3](#fmtstr-3) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8406) The type of r is const R& if ranges​::​[input_range](range.refinements#concept:input_range "25.4.6 Other range refinements [range.refinements]") is true andR& otherwise[.](#fmtstr-3.sentence-1) [4](#fmtstr-4) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8411) *Effects*: Let *s* be a basic_string such thatranges​::​equal(*s*, r) is true[.](#fmtstr-4.sentence-1) Equivalent to: return *underlying_*.format(*s*, ctx);