Files
2025-10-25 03:02:53 +03:00

490 lines
21 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[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<ranges::[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") R>
requires [same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<R, remove_cvref_t<R>>
constexpr range_format format_kind<R> = 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<R> is defined as follows:
- [(2.1)](#fmtkind-2.1)
If [same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<remove_cvref_t<ranges::range_reference_t<R>>, R> is true,format_kind<R> 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.3Qualified 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.3Qualified names[expr.prim.id.qual]") R::mapped_type is valid and denotes a type,
let U be remove_cvref_t<ranges::range_reference_t<R>>[.](#fmtkind-2.2.1.sentence-1)
If either U is a specialization of pair orU is a specialization of tuple andtuple_size_v<U> == 2,format_kind<R> is range_format::map[.](#fmtkind-2.2.1.sentence-2)
* [(2.2.2)](#fmtkind-2.2.2)
Otherwise, format_kind<R> is range_format::set[.](#fmtkind-2.2.2.sentence-1)
- [(2.3)](#fmtkind-2.3)
Otherwise, format_kind<R> 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.1Namespace std"), users may specialize format_kind for cv-unqualified program-defined types
that model ranges::[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")[.](#fmtkind-3.sentence-1)
Such specializations shall be usable in constant expressions ([[expr.const]](expr.const "7.7Constant 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 {template<class T, class charT = char>requires [same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<remove_cvref_t<T>, T> && [formattable](format.formattable#concept:formattable "28.5.6.3Concept formattable[format.formattable]")<T, charT>class range_formatter { formatter<T, charT> *underlying_*; // *exposition only* basic_string_view<charT> *separator_* = *STATICALLY-WIDEN*<charT>(", "); // *exposition only* basic_string_view<charT> *opening-bracket_* = *STATICALLY-WIDEN*<charT>("["); // *exposition only* basic_string_view<charT> *closing-bracket_* = *STATICALLY-WIDEN*<charT>("]"); // *exposition only*public:constexpr void set_separator(basic_string_view<charT> sep) noexcept; constexpr void set_brackets(basic_string_view<charT> opening,
basic_string_view<charT> closing) noexcept; constexpr formatter<T, charT>& underlying() noexcept { return *underlying_*; }constexpr const formatter<T, charT>& underlying() const noexcept { return *underlying_*; }template<class ParseContext>constexpr typename ParseContext::iterator
parse(ParseContext& ctx); template<ranges::[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") R, class FormatContext>requires [formattable](format.formattable#concept:formattable "28.5.6.3Concept formattable[format.formattable]")<ranges::range_reference_t<R>, charT> &&[same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<remove_cvref_t<ranges::range_reference_t<R>>, 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<T, charT>,
the *format-spec* in a *range-underlying-spec*, if any,
is interpreted by formatter<T, charT>[.](#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.2Standard format specifiers"))[.](#formatter-4.sentence-1)
The productions *align* and *width* are described in [[format.string]](format.string "28.5.2Format 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)<br>**Option** | **Requirements** | **Meaning** |
| --- | --- | --- |
| [🔗](#tab:formatter.range.type-row-2)<br>m | T shall be either a specialization of pair or a specialization of tuple such that tuple_size_v<T> 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)<br>[*Note [2](#tab:formatter.range.type-row-2-column-3-note-2)*:<br>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)<br>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)<br>?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.5Formatting 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<charT> 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<charT> opening,
basic_string_view<charT> 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<class ParseContext>
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<ranges::[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") R, class FormatContext>
requires [formattable](format.formattable#concept:formattable "28.5.6.3Concept formattable[format.formattable]")<ranges::range_reference_t<R>, charT> &&
[same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<remove_cvref_t<ranges::range_reference_t<R>>, 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<charT>(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<charT>(from_range, r) as an escaped string ([[format.string.escaped]](format.string.escaped "28.5.6.5Formatting 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 {template<ranges::[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") R, class charT>struct *range-default-formatter*<range_format::sequence, R, charT> { // *exposition only*private:using *maybe-const-r* = *fmt-maybe-const*<R, charT>; // *exposition only* range_formatter<remove_cvref_t<ranges::range_reference_t<*maybe-const-r*>>,
charT> *underlying_*; // *exposition only*public:constexpr void set_separator(basic_string_view<charT> sep) noexcept; constexpr void set_brackets(basic_string_view<charT> opening,
basic_string_view<charT> closing) noexcept; template<class ParseContext>constexpr typename ParseContext::iterator
parse(ParseContext& ctx); template<class FormatContext>typename FormatContext::iterator
format(*maybe-const-r*& elems, FormatContext& ctx) const; };}
[🔗](#lib:set_separator,range-default-formatter)
`constexpr void set_separator(basic_string_view<charT> 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<charT> opening,
basic_string_view<charT> 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<class ParseContext>
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<class FormatContext>
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 {template<ranges::[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") R, class charT>struct *range-default-formatter*<range_format::map, R, charT> {private:using *maybe-const-map* = *fmt-maybe-const*<R, charT>; // *exposition only*using *element-type* = // *exposition only* remove_cvref_t<ranges::range_reference_t<*maybe-const-map*>>;
range_formatter<*element-type*, charT> *underlying_*; // *exposition only*public:constexpr *range-default-formatter*(); template<class ParseContext>constexpr typename ParseContext::iterator
parse(ParseContext& ctx); template<class FormatContext>typename 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*<charT>("{"), *STATICALLY-WIDEN*<charT>("}"));*underlying_*.underlying().set_brackets({}, {});*underlying_*.underlying().set_separator(*STATICALLY-WIDEN*<charT>(": "));
[🔗](#lib:parse,range-default-formatter_)
`template<class ParseContext>
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<class FormatContext>
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 {template<ranges::[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") R, class charT>struct *range-default-formatter*<range_format::set, R, charT> {private:using *maybe-const-set* = *fmt-maybe-const*<R, charT>; // *exposition only* range_formatter<remove_cvref_t<ranges::range_reference_t<*maybe-const-set*>>,
charT> *underlying_*; // *exposition only*public:constexpr *range-default-formatter*(); template<class ParseContext>constexpr typename ParseContext::iterator
parse(ParseContext& ctx); template<class FormatContext>typename 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*<charT>("{"), *STATICALLY-WIDEN*<charT>("}"));
[🔗](#lib:parse,range-default-formatter__)
`template<class ParseContext>
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<class FormatContext>
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 {template<range_format K, ranges::[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") R, class charT>requires (K == range_format::string || K == range_format::debug_string)struct *range-default-formatter*<K, R, charT> {private: formatter<basic_string<charT>, charT> *underlying_*; // *exposition only*public:template<class ParseContext>constexpr typename ParseContext::iterator
parse(ParseContext& ctx); template<class FormatContext>typename 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.2Concept same_­as[concept.same]")<remove_cvref_t<range_reference_t<R>>, charT> is true[.](#fmtstr-1.sentence-1)
[🔗](#lib:parse,range-default-formatter___)
`template<class ParseContext>
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<class FormatContext>
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.6Other range refinements[range.refinements]")<const R> 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<charT> such thatranges::equal(*s*, r) is true[.](#fmtstr-4.sentence-1)
Equivalent to: return *underlying_*.format(*s*, ctx);