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

2678 lines
128 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]
# 28 Text processing library [[text]](./#text)
## 28.5 Formatting [format]
### [28.5.1](#syn) Header <format> synopsis [[format.syn]](format.syn)
[🔗](#header:%3cformat%3e)
namespace std {// [[format.context]](#context "28.5.6.7Class template basic_­format_­context"), class template basic_format_contexttemplate<class Out, class charT> class basic_format_context; using format_context = basic_format_context<*unspecified*, char>; using wformat_context = basic_format_context<*unspecified*, wchar_t>; // [[format.args]](#args "28.5.8.3Class template basic_­format_­args"), class template basic_format_argstemplate<class Context> class basic_format_args; using format_args = basic_format_args<format_context>; using wformat_args = basic_format_args<wformat_context>; // [[format.fmt.string]](#fmt.string "28.5.4Class template basic_­format_­string"), class template basic_format_stringtemplate<class charT, class... Args>struct basic_format_string; template<class charT> struct *runtime-format-string* { // *exposition only*private: basic_string_view<charT> *str*; // *exposition only*public:*runtime-format-string*(basic_string_view<charT> s) noexcept : *str*(s) {}*runtime-format-string*(const *runtime-format-string*&) = delete; *runtime-format-string*& operator=(const *runtime-format-string*&) = delete; }; *runtime-format-string*<char> runtime_format(string_view fmt) noexcept { return fmt; }*runtime-format-string*<wchar_t> runtime_format(wstring_view fmt) noexcept { return fmt; }template<class... Args>using [format_string](#lib:format_string "28.5.1Header <format> synopsis[format.syn]") = basic_format_string<char, type_identity_t<Args>...>; template<class... Args>using [wformat_string](#lib:wformat_string "28.5.1Header <format> synopsis[format.syn]") = basic_format_string<wchar_t, type_identity_t<Args>...>; // [[format.functions]](#functions "28.5.5Formatting functions"), formatting functionstemplate<class... Args> string format(format_string<Args...> fmt, Args&&... args); template<class... Args> wstring format(wformat_string<Args...> fmt, Args&&... args); template<class... Args> string format(const locale& loc, format_string<Args...> fmt, Args&&... args); template<class... Args> wstring format(const locale& loc, wformat_string<Args...> fmt, Args&&... args);
string vformat(string_view fmt, format_args args);
wstring vformat(wstring_view fmt, wformat_args args);
string vformat(const locale& loc, string_view fmt, format_args args);
wstring vformat(const locale& loc, wstring_view fmt, wformat_args args); template<class Out, class... Args> Out format_to(Out out, format_string<Args...> fmt, Args&&... args); template<class Out, class... Args> Out format_to(Out out, wformat_string<Args...> fmt, Args&&... args); template<class Out, class... Args> Out format_to(Out out, const locale& loc, format_string<Args...> fmt, Args&&... args); template<class Out, class... Args> Out format_to(Out out, const locale& loc, wformat_string<Args...> fmt, Args&&... args); template<class Out> Out vformat_to(Out out, string_view fmt, format_args args); template<class Out> Out vformat_to(Out out, wstring_view fmt, wformat_args args); template<class Out> Out vformat_to(Out out, const locale& loc, string_view fmt, format_args args); template<class Out> Out vformat_to(Out out, const locale& loc, wstring_view fmt, wformat_args args); template<class Out> struct format_to_n_result { Out out;
iter_difference_t<Out> size; }; template<class Out, class... Args> format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
format_string<Args...> fmt, Args&&... args); template<class Out, class... Args> format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
wformat_string<Args...> fmt, Args&&... args); template<class Out, class... Args> format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n, const locale& loc, format_string<Args...> fmt,
Args&&... args); template<class Out, class... Args> format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n, const locale& loc, wformat_string<Args...> fmt,
Args&&... args); template<class... Args> size_t formatted_size(format_string<Args...> fmt, Args&&... args); template<class... Args> size_t formatted_size(wformat_string<Args...> fmt, Args&&... args); template<class... Args> size_t formatted_size(const locale& loc, format_string<Args...> fmt, Args&&... args); template<class... Args> size_t formatted_size(const locale& loc, wformat_string<Args...> fmt, Args&&... args); // [[format.formatter]](#formatter "28.5.6Formatter"), formattertemplate<class T, class charT = char> struct formatter; // [[format.formatter.locking]](#formatter.locking "28.5.6.2Formatter locking"), formatter lockingtemplate<class T>constexpr bool enable_nonlocking_formatter_optimization = false; // [[format.formattable]](#formattable "28.5.6.3Concept formattable"), concept [formattable](#concept:formattable "28.5.6.3Concept formattable[format.formattable]")template<class T, class charT>concept formattable = *see below*; template<class R, class charT>concept [*const-formattable-range*](#concept:const-formattable-range "28.5.1Header <format> synopsis[format.syn]") = // *exposition only* ranges::[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")<const R> &&[formattable](#concept:formattable "28.5.6.3Concept formattable[format.formattable]")<ranges::range_reference_t<const R>, charT>; template<class R, class charT>using *fmt-maybe-const* = // *exposition only* conditional_t<[*const-formattable-range*](#concept:const-formattable-range "28.5.1Header <format> synopsis[format.syn]")<R, charT>, const R, R>; // [[format.parse.ctx]](#parse.ctx "28.5.6.6Class template basic_­format_­parse_­context"), class template basic_format_parse_contexttemplate<class charT> class basic_format_parse_context; using format_parse_context = basic_format_parse_context<char>; using wformat_parse_context = basic_format_parse_context<wchar_t>; // [[format.range]](#range "28.5.7Formatting of ranges"), formatting of ranges// [[format.range.fmtkind]](#range.fmtkind "28.5.7.1Variable template format_­kind"), variable template format_kindenum class [range_format](#lib:range_format "28.5.1Header <format> synopsis[format.syn]") {[disabled](#lib:range_format,disabled "28.5.1Header <format> synopsis[format.syn]"), [map](#lib:range_format,map "28.5.1Header <format> synopsis[format.syn]"), [set](#lib:range_format,set "28.5.1Header <format> synopsis[format.syn]"), [sequence](#lib:range_format,sequence "28.5.1Header <format> synopsis[format.syn]"), [string](#lib:range_format,string "28.5.1Header <format> synopsis[format.syn]"), [debug_string](#lib:range_format,debug_string "28.5.1Header <format> synopsis[format.syn]")}; template<class R>constexpr *unspecified* format_kind = *unspecified*; 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*; // [[format.range.formatter]](#range.formatter "28.5.7.2Class template range_­formatter"), class template range_formattertemplate<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](#concept:formattable "28.5.6.3Concept formattable[format.formattable]")<T, charT>class range_formatter; // [[format.range.fmtdef]](#range.fmtdef "28.5.7.3Class template range-default-formatter"), class template *range-default-formatter*template<range_format K, ranges::[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") R, class charT>struct *range-default-formatter*; // *exposition only*// [[format.range.fmtmap]](#range.fmtmap "28.5.7.4Specialization of range-default-formatter for maps"), [[format.range.fmtset]](#range.fmtset "28.5.7.5Specialization of range-default-formatter for sets"), [[format.range.fmtstr]](#range.fmtstr "28.5.7.6Specialization of range-default-formatter for strings"), specializations for maps, sets, and stringstemplate<ranges::[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") R, class charT>requires (format_kind<R> != range_format::disabled) &&[formattable](#concept:formattable "28.5.6.3Concept formattable[format.formattable]")<ranges::range_reference_t<R>, charT>struct formatter<R, charT> : *range-default-formatter*<format_kind<R>, R, charT> { }; template<ranges::[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") R>requires (format_kind<R> != range_format::disabled)constexpr bool enable_nonlocking_formatter_optimization<R> = false; // [[format.arguments]](#arguments "28.5.8Arguments"), arguments// [[format.arg]](#arg "28.5.8.1Class template basic_­format_­arg"), class template basic_format_argtemplate<class Context> class basic_format_arg; // [[format.arg.store]](#arg.store "28.5.8.2Class template format-arg-store"), class template *format-arg-store*template<class Context, class... Args> class *format-arg-store*; // *exposition only*template<class Context = format_context, class... Args>*format-arg-store*<Context, Args...> make_format_args(Args&... fmt_args); template<class... Args>*format-arg-store*<wformat_context, Args...> make_wformat_args(Args&... args); // [[format.error]](#error "28.5.10Class format_­error"), class format_errorclass format_error;}
[1](#syn-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L5906)
The class template format_to_n_result has the template parameters, data members, and special members specified above[.](#syn-1.sentence-1)
It has no base classes or members other than those specified[.](#syn-1.sentence-2)
### [28.5.2](#string) Format string [[format.string]](format.string)
#### [28.5.2.1](#string.general) General [[format.string.general]](format.string.general)
[1](#string.general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L5914)
A [*format string*](#def:format_string "28.5.2.1General[format.string.general]") for arguments args is
a (possibly empty) sequence of[*replacement fields*](#def:replacement_field,format_string "28.5.2.1General[format.string.general]"),[*escape sequences*](#def:escape_sequence,format_string "28.5.2.1General[format.string.general]"),
and characters other than { and }[.](#string.general-1.sentence-1)
Let charT be the character type of the format string[.](#string.general-1.sentence-2)
Each character that is not part of
a replacement field or an escape sequence
is copied unchanged to the output[.](#string.general-1.sentence-3)
An escape sequence is one of {{ or }}[.](#string.general-1.sentence-4)
It is replaced with { or }, respectively, in the output[.](#string.general-1.sentence-5)
The syntax of replacement fields is as follows:
replacement-field :
{ arg-idopt format-specifieropt }
arg-id :
0
positive-integer
positive-integer :
[*nonzero-digit*](lex.icon#nt:nonzero-digit "5.13.2Integer literals[lex.icon]")
positive-integer [*digit*](lex.name#nt:digit "5.11Identifiers[lex.name]")
nonnegative-integer :
[*digit*](lex.name#nt:digit "5.11Identifiers[lex.name]")
nonnegative-integer [*digit*](lex.name#nt:digit "5.11Identifiers[lex.name]")
[*nonzero-digit*](lex.icon#nt:nonzero-digit "5.13.2Integer literals[lex.icon]") : one of
1 2 3 4 5 6 7 8 9
[*digit*](lex.name#nt:digit "5.11Identifiers[lex.name]") : one of
0 1 2 3 4 5 6 7 8 9
format-specifier :
: format-spec
format-spec :
as specified by the formatter specialization for the argument type; cannot start with }
[2](#string.general-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L5972)
The *arg-id* field specifies the index of
the argument in args whose value is to be formatted and inserted into the output
instead of the replacement field[.](#string.general-2.sentence-1)
If there is no argument with
the index *arg-id* in args,
the string is not a format string for args[.](#string.general-2.sentence-2)
The optional *format-specifier* field
explicitly specifies a format for the replacement value[.](#string.general-2.sentence-3)
[3](#string.general-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L5983)
[*Example [1](#string.general-example-1)*: string s = format("{0}-{{", 8); // value of s is "8-{" — *end example*]
[4](#string.general-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L5990)
If all *arg-id**s* in a format string are omitted
(including those in the *format-spec*,
as interpreted by the corresponding formatter specialization),
argument indices 0, 1, 2, … will automatically be used in that order[.](#string.general-4.sentence-1)
If some *arg-id**s* are omitted and some are present,
the string is not a format string[.](#string.general-4.sentence-2)
[*Note [1](#string.general-note-1)*:
A format string cannot contain a
mixture of automatic and manual indexing[.](#string.general-4.sentence-3)
— *end note*]
[*Example [2](#string.general-example-2)*: string s0 = format("{} to {}", "a", "b"); // OK, automatic indexing string s1 = format("{1} to {0}", "a", "b"); // OK, manual indexing string s2 = format("{0} to {}", "a", "b"); // not a format string (mixing automatic and manual indexing),// ill-formed string s3 = format("{} to {1}", "a", "b"); // not a format string (mixing automatic and manual indexing),// ill-formed — *end example*]
[5](#string.general-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6012)
The *format-spec* field contains[*format specifications*](#def:format_specification,format_string "28.5.2.1General[format.string.general]") that define how the value should be presented[.](#string.general-5.sentence-1)
Each type can define its own
interpretation of the *format-spec* field[.](#string.general-5.sentence-2)
If *format-spec* does not conform
to the format specifications for
the argument type referred to by *arg-id*,
the string is not a format string for args[.](#string.general-5.sentence-3)
[*Example [3](#string.general-example-3)*:
- [(5.1)](#string.general-5.1)
For arithmetic, pointer, and string types
the *format-spec* is interpreted as a *std-format-spec* as described in [[format.string.std]](#string.std "28.5.2.2Standard format specifiers")[.](#string.general-5.1.sentence-1)
- [(5.2)](#string.general-5.2)
For chrono types
the *format-spec* is interpreted as a *chrono-format-spec* as described in [[time.format]](time.format "30.12Formatting")[.](#string.general-5.2.sentence-1)
- [(5.3)](#string.general-5.3)
For user-defined formatter specializations,
the behavior of the parse member function
determines how the *format-spec* is interpreted[.](#string.general-5.3.sentence-1)
— *end example*]
#### [28.5.2.2](#string.std) Standard format specifiers [[format.string.std]](format.string.std)
[1](#string.std-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6044)
Each formatter specialization
described in [[format.formatter.spec]](#formatter.spec "28.5.6.4Formatter specializations") for fundamental and string types
interprets *format-spec* as a*std-format-spec*[.](#string.std-1.sentence-1)
[*Note [1](#string.std-note-1)*:
The format specification can be used to specify such details as
minimum field width, alignment, padding, and decimal precision[.](#string.std-1.sentence-2)
Some of the formatting options
are only supported for arithmetic types[.](#string.std-1.sentence-3)
— *end note*]
The syntax of format specifications is as follows:
std-format-spec :
fill-and-alignopt [*sign*](lex.fcon#nt:sign "5.13.4Floating-point literals[lex.fcon]")opt #opt 0opt widthopt precisionopt Lopt typeopt
fill-and-align :
fillopt align
fill :
any character other than { or }
align : one of
< > ^
[*sign*](lex.fcon#nt:sign "5.13.4Floating-point literals[lex.fcon]") : one of
+ - space
width :
positive-integer
{ arg-idopt }
precision :
. nonnegative-integer
. { arg-idopt }
type : one of
a A b B c d e E f F g G o p P s x X ?
[2](#string.std-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6100)
Field widths are specified in [*field width units*](#def:units,field_width "28.5.2.2Standard format specifiers[format.string.std]");
the number of column positions required to display a sequence of
characters in a terminal[.](#string.std-2.sentence-1)
The [*minimum field width*](#def:field_width,minimum "28.5.2.2Standard format specifiers[format.string.std]") is the number of field width units a replacement field minimally requires of
the formatted sequence of characters produced for a format argument[.](#string.std-2.sentence-2)
The [*estimated field width*](#def:field_width,estimated "28.5.2.2Standard format specifiers[format.string.std]") is the number of field width units
that are required for the formatted sequence of characters
produced for a format argument independent of
the effects of the *width* option[.](#string.std-2.sentence-3)
The [*padding width*](#def:width,padding "28.5.2.2Standard format specifiers[format.string.std]") is the greater of 0 and
the difference of the minimum field width and the estimated field width[.](#string.std-2.sentence-4)
[*Note [2](#string.std-note-2)*:
The POSIX wcswidth function is an example of a function that,
given a string, returns the number of column positions required by
a terminal to display the string[.](#string.std-2.sentence-5)
— *end note*]
[3](#string.std-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6120)
The [*fill character*](#def:character,fill "28.5.2.2Standard format specifiers[format.string.std]") is the character denoted by
the *fill* option or,
if the *fill* option is absent, the space character[.](#string.std-3.sentence-1)
For a format specification in UTF-8, UTF-16, or UTF-32,
the fill character corresponds to a single Unicode scalar value[.](#string.std-3.sentence-2)
[*Note [3](#string.std-note-3)*:
The presence of a *fill* option
is signaled by the character following it,
which must be one of the alignment options[.](#string.std-3.sentence-3)
If the second character of *std-format-spec* is not a valid alignment option,
then it is assumed that
the *fill* and *align* options
are both absent[.](#string.std-3.sentence-4)
— *end note*]
[4](#string.std-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6137)
The *align* option applies to all argument types[.](#string.std-4.sentence-1)
The meaning of the various alignment options is as specified in Table [104](#tab:format.align "Table 104: Meaning of align options")[.](#string.std-4.sentence-2)
[*Example [1](#string.std-example-1)*: char c = 120;
string s0 = format("{:6}", 42); // value of s0 is " 42" string s1 = format("{:6}", 'x'); // value of s1 is "x " string s2 = format("{:*<6}", 'x'); // value of s2 is "x*****" string s3 = format("{:*>6}", 'x'); // value of s3 is "*****x" string s4 = format("{:*^6}", 'x'); // value of s4 is "**x***" string s5 = format("{:6d}", c); // value of s5 is " 120" string s6 = format("{:6}", true); // value of s6 is "true " string s7 = format("{:*<6.3}", "123456"); // value of s7 is "123***" string s8 = format("{:02}", 1234); // value of s8 is "1234" string s9 = format("{:*<}", "12"); // value of s9 is "12" string sA = format("{:*<6}", "12345678"); // value of sA is "12345678" string sB = format("{:🤡^6}", "x"); // value of sB is "🤡🤡Ÿ¤¡ðŸ¤¡ðŸ¤¡" string sC = format("{:*^6}", "🤡🤡🤡"); // value of sC is "🤡🤡🤡" — *end example*]
[*Note [4](#string.std-note-4)*:
The *fill*, *align*, and 0 options
have no effect when the minimum field width
is not greater than the estimated field width
because padding width is 0 in that case[.](#string.std-4.sentence-3)
Since fill characters are assumed to have a field width of 1,
use of a character with a different field width can produce misaligned output[.](#string.std-4.sentence-4)
The 🤡 (U+1f921 clown face) character has a field width of 2[.](#string.std-4.sentence-5)
The examples above that include that character
illustrate the effect of the field width
when that character is used as a fill character
as opposed to when it is used as a formatting argument[.](#string.std-4.sentence-6)
— *end note*]
Table [104](#tab:format.align) Meaning of *align* options [[tab:format.align]](./tab:format.align)
| [🔗](#tab:format.align-row-1)<br>**Option** | **Meaning** |
| --- | --- |
| [🔗](#tab:format.align-row-2)<br>< | Forces the formatted argument to be aligned to the start of the field by inserting n fill characters after the formatted argument where n is the padding width[.](#tab:format.align-row-2-column-2-sentence-1)<br>This is the default for non-arithmetic non-pointer types, charT, and bool, unless an integer presentation type is specified[.](#tab:format.align-row-2-column-2-sentence-2) |
| [🔗](#tab:format.align-row-3)<br>> | Forces the formatted argument to be aligned to the end of the field by inserting n fill characters before the formatted argument where n is the padding width[.](#tab:format.align-row-3-column-2-sentence-1)<br>This is the default for arithmetic types other than charT and bool, pointer types, or when an integer presentation type is specified[.](#tab:format.align-row-3-column-2-sentence-2) |
| [🔗](#tab:format.align-row-4)<br>^ | Forces the formatted argument to be centered within the field by inserting ⌊n2⌋ fill characters before and ⌈n2⌉ fill characters after the formatted argument, where n is the padding width[.](#tab:format.align-row-4-column-2-sentence-1) |
[5](#string.std-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6205)
The *sign* option is only valid
for arithmetic types other than charT and bool or when an integer presentation type is specified[.](#string.std-5.sentence-1)
The meaning of the various options is as specified in Table [105](#tab:format.sign "Table 105: Meaning of sign options")[.](#string.std-5.sentence-2)
Table [105](#tab:format.sign) — Meaning of *sign* options [[tab:format.sign]](./tab:format.sign)
| [🔗](#tab:format.sign-row-1)<br>**Option** | **Meaning** |
| --- | --- |
| [🔗](#tab:format.sign-row-2)<br>+ | Indicates that a sign should be used for both non-negative and negative numbers[.](#tab:format.sign-row-2-column-2-sentence-1)<br>The + sign is inserted before the output of to_chars for non-negative numbers other than negative zero[.](#tab:format.sign-row-2-column-2-sentence-2)<br>[*Note [5](#tab:format.sign-row-2-column-2-note-5)*:<br>For negative numbers and negative zero the output of to_chars will already contain the sign so no additional transformation is performed[.](#tab:format.sign-row-2-column-2-sentence-3) — *end note*] |
| [🔗](#tab:format.sign-row-3)<br>- | Indicates that a sign should be used for negative numbers and negative zero only (this is the default behavior)[.](#tab:format.sign-row-3-column-2-sentence-1) |
| [🔗](#tab:format.sign-row-4)<br>space | Indicates that a leading space should be used for non-negative numbers other than negative zero, and a minus sign for negative numbers and negative zero[.](#tab:format.sign-row-4-column-2-sentence-1) |
[6](#string.std-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6238)
The *sign* option applies to floating-point infinity and NaN.
[*Example [2](#string.std-example-2)*: double inf = numeric_limits<double>::infinity();double nan = numeric_limits<double>::quiet_NaN();
string s0 = format("{0:},{0:+},{0:-},{0: }", 1); // value of s0 is "1,+1,1, 1" string s1 = format("{0:},{0:+},{0:-},{0: }", -1); // value of s1 is "-1,-1,-1,-1" string s2 = format("{0:},{0:+},{0:-},{0: }", inf); // value of s2 is "inf,+inf,inf, inf" string s3 = format("{0:},{0:+},{0:-},{0: }", nan); // value of s3 is "nan,+nan,nan, nan" — *end example*]
[7](#string.std-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6251)
The # option causes the[*alternate form*](#def:alternate_form,format_string "28.5.2.2Standard format specifiers[format.string.std]") to be used for the conversion[.](#string.std-7.sentence-1)
This option is valid for arithmetic types other thancharT and bool or when an integer presentation type is specified, and not otherwise[.](#string.std-7.sentence-2)
For integral types,
the alternate form inserts the
base prefix (if any) specified in Table [107](#tab:format.type.int "Table 107: Meaning of type options for integer types") into the output after the sign character (possibly space) if there is one, or
before the output of to_chars otherwise[.](#string.std-7.sentence-3)
For floating-point types,
the alternate form causes the result of the conversion of finite values
to always contain a decimal-point character,
even if no digits follow it[.](#string.std-7.sentence-4)
Normally, a decimal-point character appears in the result of these
conversions only if a digit follows it[.](#string.std-7.sentence-5)
In addition, for g and G conversions,
trailing zeros are not removed from the result[.](#string.std-7.sentence-6)
[8](#string.std-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6276)
The 0 option is valid for arithmetic types
other than charT and bool, pointer types, or
when an integer presentation type is specified[.](#string.std-8.sentence-1)
For formatting arguments that have a value
other than an infinity or a NaN,
this option pads the formatted argument by
inserting the 0 character n times
following the sign or base prefix indicators (if any)
where n is 0 if the *align* option is present and
is the padding width otherwise[.](#string.std-8.sentence-2)
[*Example [3](#string.std-example-3)*: char c = 120;
string s1 = format("{:+06d}", c); // value of s1 is "+00120" string s2 = format("{:#06x}", 0xa); // value of s2 is "0x000a" string s3 = format("{:<06}", -42); // value of s3 is "-42 " (0 has no effect) string s4 = format("{:06}", inf); // value of s4 is " inf" (0 has no effect) — *end example*]
[9](#string.std-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6297)
The *width* option specifies the minimum field width[.](#string.std-9.sentence-1)
If the *width* option is absent,
the minimum field width is 0[.](#string.std-9.sentence-2)
[10](#string.std-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6302)
If { *arg-id*opt } is used in
a *width* or *precision* option,
the value of the corresponding formatting argument is used as the value of the option[.](#string.std-10.sentence-1)
The option is valid only if the corresponding formatting argument is
of standard signed or unsigned integer type[.](#string.std-10.sentence-2)
If its value is negative,
an exception of type format_error is thrown[.](#string.std-10.sentence-3)
[11](#string.std-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6311)
If *positive-integer* is used in a*width* option, the value of the *positive-integer* is interpreted as a decimal integer and used as the value of the option[.](#string.std-11.sentence-1)
[12](#string.std-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6317)
For the purposes of width computation,
a string is assumed to be in
a locale-independent,implementation-defined encoding[.](#string.std-12.sentence-1)
Implementations should use either UTF-8, UTF-16, or UTF-32,
on platforms capable of displaying Unicode text in a terminal[.](#string.std-12.sentence-2)
[*Note [6](#string.std-note-6)*:
This is the case for Windows®-based[237](#footnote-237 "Windows®&nbsp;is a registered trademark of Microsoft Corporation. This information is given for the convenience of users of this document and does not constitute an endorsement by ISO or IEC of this product.") and many POSIX-based operating systems[.](#string.std-12.sentence-3)
— *end note*]
[13](#string.std-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6334)
For a sequence of characters in UTF-8, UTF-16, or UTF-32,
an implementation should use as its field width
the sum of the field widths of the first code point
of each extended grapheme cluster[.](#string.std-13.sentence-1)
Extended grapheme clusters are defined by UAX #29 of the Unicode Standard[.](#string.std-13.sentence-2)
The following code points have a field width of 2:
- [(13.1)](#string.std-13.1)
any code point with the East_Asian_Width="W" orEast_Asian_Width="F" property as described by
UAX #44 of the Unicode Standard
- [(13.2)](#string.std-13.2)
U+4dc0 – U+4dff (Yijing Hexagram Symbols)
- [(13.3)](#string.std-13.3)
U+1f300 – U+1f5ff (Miscellaneous Symbols and Pictographs)
- [(13.4)](#string.std-13.4)
U+1f900 – U+1f9ff (Supplemental Symbols and Pictographs)
The field width of all other code points is 1[.](#string.std-13.sentence-3)
[14](#string.std-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6355)
For a sequence of characters in neither UTF-8, UTF-16, nor UTF-32,
the field width is unspecified[.](#string.std-14.sentence-1)
[15](#string.std-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6359)
The *precision* option is valid
for floating-point and string types[.](#string.std-15.sentence-1)
For floating-point types,
the value of this option specifies the precision
to be used for the floating-point presentation type[.](#string.std-15.sentence-2)
For string types,
this option specifies the longest prefix of the formatted argument
to be included in the replacement field such that
the field width of the prefix is no greater than the value of this option[.](#string.std-15.sentence-3)
[16](#string.std-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6370)
If *nonnegative-integer* is used in
a *precision* option,
the value of the decimal integer is used as the value of the option[.](#string.std-16.sentence-1)
[17](#string.std-17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6375)
When the L option is used, the form used for the conversion is called
the [*locale-specific form*](#def:locale-specific_form,format_string "28.5.2.2Standard format specifiers[format.string.std]")[.](#string.std-17.sentence-1)
The L option is only valid for arithmetic types, and
its effect depends upon the type[.](#string.std-17.sentence-2)
- [(17.1)](#string.std-17.1)
For integral types, the locale-specific form
causes the context's locale to be used
to insert the appropriate digit group separator characters[.](#string.std-17.1.sentence-1)
- [(17.2)](#string.std-17.2)
For floating-point types, the locale-specific form
causes the context's locale to be used
to insert the appropriate digit group and radix separator characters[.](#string.std-17.2.sentence-1)
- [(17.3)](#string.std-17.3)
For the textual representation of bool, the locale-specific form
causes the context's locale to be used
to insert the appropriate string as if obtained
with numpunct::truename or numpunct::falsename[.](#string.std-17.3.sentence-1)
[18](#string.std-18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6398)
The *type* determines how the data should be presented[.](#string.std-18.sentence-1)
[19](#string.std-19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6401)
The available string presentation types are specified in Table [106](#tab:format.type.string "Table 106: Meaning of type options for strings")[.](#string.std-19.sentence-1)
Table [106](#tab:format.type.string) Meaning of *type* options for strings [[tab:format.type.string]](./tab:format.type.string)
| [🔗](#tab:format.type.string-row-1)<br>**Type** | **Meaning** |
| --- | --- |
| [🔗](#tab:format.type.string-row-2)<br>none, s | Copies the string to the output[.](#tab:format.type.string-row-2-column-2-sentence-1) |
| [🔗](#tab:format.type.string-row-3)<br>? | Copies the escaped string ([[format.string.escaped]](#string.escaped "28.5.6.5Formatting escaped characters and strings")) to the output[.](#tab:format.type.string-row-3-column-2-sentence-1) |
[20](#string.std-20)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6417)
The meaning of some non-string presentation types
is defined in terms of a call to to_chars[.](#string.std-20.sentence-1)
In such cases,
let [first, last) be a range
large enough to hold the to_chars output
and value be the formatting argument value[.](#string.std-20.sentence-2)
Formatting is done as if by calling to_chars as specified
and copying the output through the output iterator of the format context[.](#string.std-20.sentence-3)
[*Note [7](#string.std-note-7)*:
Additional padding and adjustments are performed
prior to copying the output through the output iterator
as specified by the format specifiers[.](#string.std-20.sentence-4)
— *end note*]
[21](#string.std-21)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6432)
The available integer presentation types
for integral types other than bool and charT are specified in Table [107](#tab:format.type.int "Table 107: Meaning of type options for integer types")[.](#string.std-21.sentence-1)
[*Example [4](#string.std-example-4)*: string s0 = format("{}", 42); // value of s0 is "42" string s1 = format("{0:b} {0:d} {0:o} {0:x}", 42); // value of s1 is "101010 42 52 2a" string s2 = format("{0:#x} {0:#X}", 42); // value of s2 is "0x2a 0X2A" string s3 = format("{:L}", 1234); // value of s3 can be "1,234"// (depending on the locale) — *end example*]
Table [107](#tab:format.type.int) — Meaning of *type* options for integer types [[tab:format.type.int]](./tab:format.type.int)
| [🔗](#tab:format.type.int-row-1)<br>**Type** | **Meaning** |
| --- | --- |
| [🔗](#tab:format.type.int-row-2)<br>b | to_chars(first, last, value, 2); the base prefix is 0b[.](#tab:format.type.int-row-2-column-2-sentence-1) |
| [🔗](#tab:format.type.int-row-3)<br>B | The same as b, except that the base prefix is 0B[.](#tab:format.type.int-row-3-column-2-sentence-1) |
| [🔗](#tab:format.type.int-row-4)<br>c | Copies the character static_cast<charT>(value) to the output[.](#tab:format.type.int-row-4-column-2-sentence-1)<br>Throws format_error if value is not in the range of representable values for charT[.](#tab:format.type.int-row-4-column-2-sentence-2) |
| [🔗](#tab:format.type.int-row-5)<br>d | to_chars(first, last, value)[.](#tab:format.type.int-row-5-column-2-sentence-1) |
| [🔗](#tab:format.type.int-row-6)<br>o | to_chars(first, last, value, 8); the base prefix is 0 if value is nonzero and is empty otherwise[.](#tab:format.type.int-row-6-column-2-sentence-1) |
| [🔗](#tab:format.type.int-row-7)<br>x | to_chars(first, last, value, 16); the base prefix is 0x[.](#tab:format.type.int-row-7-column-2-sentence-1) |
| [🔗](#tab:format.type.int-row-8)<br>X | The same as x, except that it uses uppercase letters for digits above 9 and the base prefix is 0X[.](#tab:format.type.int-row-8-column-2-sentence-1) |
| [🔗](#tab:format.type.int-row-9)<br>none | The same as d[.](#tab:format.type.int-row-9-column-2-sentence-1)<br>[*Note [8](#tab:format.type.int-row-9-column-2-note-8)*:<br>If the formatting argument type is charT or bool, the default is instead c or s, respectively[.](#tab:format.type.int-row-9-column-2-sentence-2) — *end note*] |
[22](#string.std-22)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6499)
The available charT presentation types are specified in Table [108](#tab:format.type.char "Table 108: Meaning of type options for charT")[.](#string.std-22.sentence-1)
Table [108](#tab:format.type.char) — Meaning of *type* options for charT [[tab:format.type.char]](./tab:format.type.char)
| [🔗](#tab:format.type.char-row-1)<br>**Type** | **Meaning** |
| --- | --- |
| [🔗](#tab:format.type.char-row-2)<br>none, c | Copies the character to the output[.](#tab:format.type.char-row-2-column-2-sentence-1) |
| [🔗](#tab:format.type.char-row-3)<br>b, B, d, o, x, X | As specified in Table [107](#tab:format.type.int "Table 107: Meaning of type options for integer types") with value converted to the unsigned version of the underlying type[.](#tab:format.type.char-row-3-column-2-sentence-1) |
| [🔗](#tab:format.type.char-row-4)<br>? | Copies the escaped character ([[format.string.escaped]](#string.escaped "28.5.6.5Formatting escaped characters and strings")) to the output[.](#tab:format.type.char-row-4-column-2-sentence-1) |
[23](#string.std-23)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6519)
The available bool presentation types are specified in Table [109](#tab:format.type.bool "Table 109: Meaning of type options for bool")[.](#string.std-23.sentence-1)
Table [109](#tab:format.type.bool) — Meaning of *type* options for bool [[tab:format.type.bool]](./tab:format.type.bool)
| [🔗](#tab:format.type.bool-row-1)<br>**Type** | **Meaning** |
| --- | --- |
| [🔗](#tab:format.type.bool-row-2)<br>none, s | Copies textual representation, either true or false, to the output[.](#tab:format.type.bool-row-2-column-2-sentence-1) |
| [🔗](#tab:format.type.bool-row-3)<br>b, B, d, o, x, X | As specified in Table [107](#tab:format.type.int "Table 107: Meaning of type options for integer types") for the value static_cast<unsigned char>(value)[.](#tab:format.type.bool-row-3-column-2-sentence-1) |
[24](#string.std-24)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6537)
The available floating-point presentation types and their meanings
for values other than infinity and NaN are
specified in Table [110](#tab:format.type.float "Table 110: Meaning of type options for floating-point types")[.](#string.std-24.sentence-1)
For lower-case presentation types, infinity and NaN are formatted asinf and nan, respectively[.](#string.std-24.sentence-2)
For upper-case presentation types, infinity and NaN are formatted asINF and NAN, respectively[.](#string.std-24.sentence-3)
[*Note [9](#string.std-note-9)*:
In either case, a sign is included
if indicated by the *sign* option[.](#string.std-24.sentence-4)
— *end note*]
Table [110](#tab:format.type.float) — Meaning of *type* options for floating-point types [[tab:format.type.float]](./tab:format.type.float)
| [🔗](#tab:format.type.float-row-1)<br>**Type** | **Meaning** |
| --- | --- |
| [🔗](#tab:format.type.float-row-2)<br>a | If *precision* is specified, equivalent to to_chars(first, last, value, chars_format::hex, precision) where precision is the specified formatting precision; equivalent to to_chars(first, last, value, chars_format::hex) otherwise[.](#tab:format.type.float-row-2-column-2-sentence-1) |
| [🔗](#tab:format.type.float-row-3)<br>A | The same as a, except that it uses uppercase letters for digits above 9 and P to indicate the exponent[.](#tab:format.type.float-row-3-column-2-sentence-1) |
| [🔗](#tab:format.type.float-row-4)<br>e | Equivalent to to_chars(first, last, value, chars_format::scientific, precision) where precision is the specified formatting precision, or 6 if *precision* is not specified[.](#tab:format.type.float-row-4-column-2-sentence-1) |
| [🔗](#tab:format.type.float-row-5)<br>E | The same as e, except that it uses E to indicate exponent[.](#tab:format.type.float-row-5-column-2-sentence-1) |
| [🔗](#tab:format.type.float-row-6)<br>f, F | Equivalent to to_chars(first, last, value, chars_format::fixed, precision) where precision is the specified formatting precision, or 6 if *precision* is not specified[.](#tab:format.type.float-row-6-column-2-sentence-1) |
| [🔗](#tab:format.type.float-row-7)<br>g | Equivalent to to_chars(first, last, value, chars_format::general, precision) where precision is the specified formatting precision, or 6 if *precision* is not specified[.](#tab:format.type.float-row-7-column-2-sentence-1) |
| [🔗](#tab:format.type.float-row-8)<br>G | The same as g, except that it uses E to indicate exponent[.](#tab:format.type.float-row-8-column-2-sentence-1) |
| [🔗](#tab:format.type.float-row-9)<br>none | If *precision* is specified, equivalent to to_chars(first, last, value, chars_format::general, precision) where precision is the specified formatting precision; equivalent to to_chars(first, last, value) otherwise[.](#tab:format.type.float-row-9-column-2-sentence-1) |
[25](#string.std-25)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6621)
The available pointer presentation types and their mapping toto_chars are specified in Table [111](#tab:format.type.ptr "Table 111: Meaning of type options for pointer types")[.](#string.std-25.sentence-1)
[*Note [10](#string.std-note-10)*:
Pointer presentation types also apply to nullptr_t[.](#string.std-25.sentence-2)
— *end note*]
Table [111](#tab:format.type.ptr) — Meaning of *type* options for pointer types [[tab:format.type.ptr]](./tab:format.type.ptr)
| [🔗](#tab:format.type.ptr-row-1)<br>**Type** | **Meaning** |
| --- | --- |
| [🔗](#tab:format.type.ptr-row-2)<br>none, p | If uintptr_t is defined, to_chars(first, last, reinterpret_cast<uintptr_t>(value), 16) with the prefix 0x inserted immediately before the output of to_chars; otherwise, implementation-defined[.](#tab:format.type.ptr-row-2-column-2-sentence-1) |
| [🔗](#tab:format.type.ptr-row-3)<br>P | The same as p, except that it uses uppercase letters for digits above 9 and the base prefix is 0X[.](#tab:format.type.ptr-row-3-column-2-sentence-1) |
[237)](#footnote-237)[237)](#footnoteref-237)
Windows® is a registered trademark of Microsoft Corporation[.](#footnote-237.sentence-1)
This information is given for the convenience of users of this document and
does not constitute an endorsement by ISO or IEC of this product[.](#footnote-237.sentence-2)
### [28.5.3](#err.report) Error reporting [[format.err.report]](format.err.report)
[1](#err.report-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6648)
Formatting functions throw format_error if
an argument fmt is passed that
is not a format string for args[.](#err.report-1.sentence-1)
They propagate exceptions thrown by operations offormatter specializations and iterators[.](#err.report-1.sentence-2)
Failure to allocate storage is reported by
throwing an exception as described in [[res.on.exception.handling]](res.on.exception.handling "16.4.6.14Restrictions on exception handling")[.](#err.report-1.sentence-3)
### [28.5.4](#fmt.string) Class template basic_format_string [[format.fmt.string]](format.fmt.string)
namespace std {template<class charT, class... Args>struct [basic_format_string](#lib:basic_format_string "28.5.4Class template basic_­format_­string[format.fmt.string]") {private: basic_string_view<charT> *str*; // *exposition only*public:template<class T> consteval basic_format_string(const T& s);
basic_format_string(*runtime-format-string*<charT> s) noexcept : str(s.*str*) {}constexpr basic_string_view<charT> get() const noexcept { return *str*; }};}
[🔗](#fmt.string-itemdecl:1)
`template<class T> consteval basic_format_string(const T& s);
`
[1](#fmt.string-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6680)
*Constraints*: const T& models [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<basic_string_view<charT>>[.](#fmt.string-1.sentence-1)
[2](#fmt.string-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6684)
*Effects*: Direct-non-list-initializes *str* with s[.](#fmt.string-2.sentence-1)
[3](#fmt.string-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6688)
*Remarks*: A call to this function is not a core constant expression ([[expr.const]](expr.const "7.7Constant expressions"))
unless there exist args of types Args such that *str* is a format string for args[.](#fmt.string-3.sentence-1)
### [28.5.5](#functions) Formatting functions [[format.functions]](format.functions)
[1](#functions-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6697)
In the description of the functions, operator + is used
for some of the iterator categories for which it does not have to be defined[.](#functions-1.sentence-1)
In these cases the semantics of a + n are
the same as in [[algorithms.requirements]](algorithms.requirements "26.2Algorithms requirements")[.](#functions-1.sentence-2)
[🔗](#lib:format)
`template<class... Args>
string format(format_string<Args...> fmt, Args&&... args);
`
[2](#functions-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6710)
*Effects*: Equivalent to:return vformat(fmt.*str*, make_format_args(args...));
[🔗](#lib:format_)
`template<class... Args>
wstring format(wformat_string<Args...> fmt, Args&&... args);
`
[3](#functions-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6725)
*Effects*: Equivalent to:return vformat(fmt.*str*, make_wformat_args(args...));
[🔗](#lib:format__)
`template<class... Args>
string format(const locale& loc, format_string<Args...> fmt, Args&&... args);
`
[4](#functions-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6740)
*Effects*: Equivalent to:return vformat(loc, fmt.*str*, make_format_args(args...));
[🔗](#lib:format___)
`template<class... Args>
wstring format(const locale& loc, wformat_string<Args...> fmt, Args&&... args);
`
[5](#functions-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6755)
*Effects*: Equivalent to:return vformat(loc, fmt.*str*, make_wformat_args(args...));
[🔗](#lib:vformat)
`string vformat(string_view fmt, format_args args);
wstring vformat(wstring_view fmt, wformat_args args);
string vformat(const locale& loc, string_view fmt, format_args args);
wstring vformat(const locale& loc, wstring_view fmt, wformat_args args);
`
[6](#functions-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6772)
*Returns*: A string object holding the character representation of
formatting arguments provided by args formatted according to
specifications given in fmt[.](#functions-6.sentence-1)
If present, loc is used for locale-specific formatting[.](#functions-6.sentence-2)
[7](#functions-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6779)
*Throws*: As specified in [[format.err.report]](#err.report "28.5.3Error reporting")[.](#functions-7.sentence-1)
[🔗](#lib:format_to)
`template<class Out, class... Args>
Out format_to(Out out, format_string<Args...> fmt, Args&&... args);
`
[8](#functions-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6791)
*Effects*: Equivalent to:return vformat_to(std::move(out), fmt.*str*, make_format_args(args...));
[🔗](#lib:format_to_)
`template<class Out, class... Args>
Out format_to(Out out, wformat_string<Args...> fmt, Args&&... args);
`
[9](#functions-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6806)
*Effects*: Equivalent to:return vformat_to(std::move(out), fmt.*str*, make_wformat_args(args...));
[🔗](#lib:format_to__)
`template<class Out, class... Args>
Out format_to(Out out, const locale& loc, format_string<Args...> fmt, Args&&... args);
`
[10](#functions-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6821)
*Effects*: Equivalent to:return vformat_to(std::move(out), loc, fmt.*str*, make_format_args(args...));
[🔗](#lib:format_to___)
`template<class Out, class... Args>
Out format_to(Out out, const locale& loc, wformat_string<Args...> fmt, Args&&... args);
`
[11](#functions-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6836)
*Effects*: Equivalent to:return vformat_to(std::move(out), loc, fmt.*str*, make_wformat_args(args...));
[🔗](#lib:vformat_to)
`template<class Out>
Out vformat_to(Out out, string_view fmt, format_args args);
template<class Out>
Out vformat_to(Out out, wstring_view fmt, wformat_args args);
template<class Out>
Out vformat_to(Out out, const locale& loc, string_view fmt, format_args args);
template<class Out>
Out vformat_to(Out out, const locale& loc, wstring_view fmt, wformat_args args);
`
[12](#functions-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6857)
Let charT be decltype(fmt)::value_type[.](#functions-12.sentence-1)
[13](#functions-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6860)
*Constraints*: Out satisfies [output_iterator](iterator.concept.output#concept:output_iterator "24.3.4.10Concept output_­iterator[iterator.concept.output]")<const charT&>[.](#functions-13.sentence-1)
[14](#functions-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6864)
*Preconditions*: Out models [output_iterator](iterator.concept.output#concept:output_iterator "24.3.4.10Concept output_­iterator[iterator.concept.output]")<const charT&>[.](#functions-14.sentence-1)
[15](#functions-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6868)
*Effects*: Places the character representation of formatting
the arguments provided by args,
formatted according to the specifications given in fmt,
into the range [out, out + N),
where N is the number of characters in that character representation[.](#functions-15.sentence-1)
If present, loc is used for locale-specific formatting[.](#functions-15.sentence-2)
[16](#functions-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6877)
*Returns*: out + N[.](#functions-16.sentence-1)
[17](#functions-17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6881)
*Throws*: As specified in [[format.err.report]](#err.report "28.5.3Error reporting")[.](#functions-17.sentence-1)
[🔗](#lib:format_to_n)
`template<class Out, class... Args>
format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
format_string<Args...> fmt, Args&&... args);
template<class Out, class... Args>
format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
wformat_string<Args...> fmt, Args&&... args);
template<class Out, class... Args>
format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
const locale& loc, format_string<Args...> fmt,
Args&&... args);
template<class Out, class... Args>
format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
const locale& loc, wformat_string<Args...> fmt,
Args&&... args);
`
[18](#functions-18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6905)
Let
- [(18.1)](#functions-18.1)
charT be decltype(fmt.*str*)::value_type,
- [(18.2)](#functions-18.2)
N beformatted_size(fmt, args...) for the functions without a loc parameter andformatted_size(loc, fmt, args...) for the functions with a loc parameter, and
- [(18.3)](#functions-18.3)
M be clamp(n, 0, N)[.](#functions-18.sentence-1)
[19](#functions-19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6915)
*Constraints*: Out satisfies [output_iterator](iterator.concept.output#concept:output_iterator "24.3.4.10Concept output_­iterator[iterator.concept.output]")<const charT&>[.](#functions-19.sentence-1)
[20](#functions-20)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6919)
*Preconditions*: Out models [output_iterator](iterator.concept.output#concept:output_iterator "24.3.4.10Concept output_­iterator[iterator.concept.output]")<const charT&>, andformatter<remove_cvref_t<Ti>, charT> meets the *BasicFormatter* requirements ([[formatter.requirements]](#formatter.requirements "28.5.6.1Formatter requirements"))
for each Ti in Args[.](#functions-20.sentence-1)
[21](#functions-21)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6926)
*Effects*: Places the first M characters of the character representation of
formatting the arguments provided by args,
formatted according to the specifications given in fmt,
into the range [out, out + M)[.](#functions-21.sentence-1)
If present, loc is used for locale-specific formatting[.](#functions-21.sentence-2)
[22](#functions-22)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6934)
*Returns*: {out + M, N}[.](#functions-22.sentence-1)
[23](#functions-23)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6938)
*Throws*: As specified in [[format.err.report]](#err.report "28.5.3Error reporting")[.](#functions-23.sentence-1)
[🔗](#lib:formatted_size)
`template<class... Args>
size_t formatted_size(format_string<Args...> fmt, Args&&... args);
template<class... Args>
size_t formatted_size(wformat_string<Args...> fmt, Args&&... args);
template<class... Args>
size_t formatted_size(const locale& loc, format_string<Args...> fmt, Args&&... args);
template<class... Args>
size_t formatted_size(const locale& loc, wformat_string<Args...> fmt, Args&&... args);
`
[24](#functions-24)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6956)
Let charT be decltype(fmt.*str*)::value_type[.](#functions-24.sentence-1)
[25](#functions-25)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6959)
*Preconditions*: formatter<remove_cvref_t<Ti>, charT> meets the *BasicFormatter* requirements ([[formatter.requirements]](#formatter.requirements "28.5.6.1Formatter requirements"))
for each Ti in Args[.](#functions-25.sentence-1)
[26](#functions-26)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6965)
*Returns*: The number of characters in the character representation of
formatting arguments args formatted according to specifications given in fmt[.](#functions-26.sentence-1)
If present, loc is used for locale-specific formatting[.](#functions-26.sentence-2)
[27](#functions-27)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6972)
*Throws*: As specified in [[format.err.report]](#err.report "28.5.3Error reporting")[.](#functions-27.sentence-1)
### [28.5.6](#formatter) Formatter [[format.formatter]](format.formatter)
#### [28.5.6.1](#formatter.requirements) Formatter requirements [[formatter.requirements]](formatter.requirements)
[1](#formatter.requirements-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6981)
A type F meets the *BasicFormatter* requirements if
it meets the
- [(1.1)](#formatter.requirements-1.1)
*Cpp17DefaultConstructible* (Table [30](utility.arg.requirements#tab:cpp17.defaultconstructible "Table 30: Cpp17DefaultConstructible requirements")),
- [(1.2)](#formatter.requirements-1.2)
*Cpp17CopyConstructible* (Table [32](utility.arg.requirements#tab:cpp17.copyconstructible "Table 32: Cpp17CopyConstructible requirements (in addition to Cpp17MoveConstructible)")),
- [(1.3)](#formatter.requirements-1.3)
*Cpp17CopyAssignable* (Table [34](utility.arg.requirements#tab:cpp17.copyassignable "Table 34: Cpp17CopyAssignable requirements (in addition to Cpp17MoveAssignable)")),
- [(1.4)](#formatter.requirements-1.4)
*Cpp17Swappable* ([[swappable.requirements]](swappable.requirements "16.4.4.3Swappable requirements")), and
- [(1.5)](#formatter.requirements-1.5)
*Cpp17Destructible* (Table [35](utility.arg.requirements#tab:cpp17.destructible "Table 35: Cpp17Destructible requirements"))
requirements, and
the expressions shown in Table [112](#tab:formatter.basic "Table 112: BasicFormatter requirements") are valid and
have the indicated semantics[.](#formatter.requirements-1.sentence-1)
[2](#formatter.requirements-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L6995)
A type F meets the *Formatter* requirements
if it meets the *BasicFormatter* requirements and
the expressions shown in Table [113](#tab:formatter "Table 113: Formatter requirements") are valid and
have the indicated semantics[.](#formatter.requirements-2.sentence-1)
[3](#formatter.requirements-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7001)
Given character type charT, output iterator typeOut, and formatting argument type T,
in Table [112](#tab:formatter.basic "Table 112: BasicFormatter requirements") and Table [113](#tab:formatter "Table 113: Formatter requirements"):
- [(3.1)](#formatter.requirements-3.1)
f is a value of type (possibly const) F,
- [(3.2)](#formatter.requirements-3.2)
g is an lvalue of type F,
- [(3.3)](#formatter.requirements-3.3)
u is an lvalue of type T,
- [(3.4)](#formatter.requirements-3.4)
t is a value of a type convertible to (possibly const) T,
- [(3.5)](#formatter.requirements-3.5)
PC is basic_format_parse_context<charT>,
- [(3.6)](#formatter.requirements-3.6)
FC is basic_format_context<Out, charT>,
- [(3.7)](#formatter.requirements-3.7)
pc is an lvalue of type PC, and
- [(3.8)](#formatter.requirements-3.8)
fc is an lvalue of type FC[.](#formatter.requirements-3.sentence-1)
pc.begin() points to the beginning of the*format-spec* ([[format.string]](#string "28.5.2Format string"))
of the replacement field being formatted
in the format string[.](#formatter.requirements-3.sentence-2)
If *format-spec* is not present or empty then eitherpc.begin() == pc.end() or*pc.begin() == '}'[.](#formatter.requirements-3.sentence-3)
Table [112](#tab:formatter.basic) — *BasicFormatter* requirements [[tab:formatter.basic]](./tab:formatter.basic)
| [🔗](#tab:formatter.basic-row-1)<br>**Expression** | **Return type** | **Requirement** |
| --- | --- | --- |
| [🔗](#tab:formatter.basic-row-2)<br>g.parse(pc) | PC::iterator | Parses *format-spec* ([[format.string]](#string "28.5.2Format string")) for type T in the range [pc.begin(), pc.end()) until the first unmatched character[.](#tab:formatter.basic-row-2-column-3-sentence-1)<br>Throws format_error unless the whole range is parsed or the unmatched character is }[.](#tab:formatter.basic-row-2-column-3-sentence-2)<br>[*Note [1](#tab:formatter.basic-row-2-column-3-note-1)*:<br>This allows formatters to emit meaningful error messages[.](#tab:formatter.basic-row-2-column-3-sentence-3) — *end note*]<br> Stores the parsed format specifiers in *this and returns an iterator past the end of the parsed range[.](#tab:formatter.basic-row-2-column-3-sentence-4) |
| [🔗](#tab:formatter.basic-row-3)<br>f.format(u, fc) | FC::iterator | Formats u according to the specifiers stored in *this, writes the output to fc.out(), and returns an iterator past the end of the output range[.](#tab:formatter.basic-row-3-column-3-sentence-1)<br>The output shall only depend on u, fc.locale(), fc.arg(n) for any value n of type size_t, and the range [pc.begin(), pc.end()) from the last call to f.parse(pc)[.](#tab:formatter.basic-row-3-column-3-sentence-2) |
Table [113](#tab:formatter) — *Formatter* requirements [[tab:formatter]](./tab:formatter)
| [🔗](#tab:formatter-row-1)<br>**Expression** | **Return type** | **Requirement** |
| --- | --- | --- |
| [🔗](#tab:formatter-row-2)<br>f.format(t, fc) | FC::iterator | Formats t according to the specifiers stored in *this, writes the output to fc.out(), and returns an iterator past the end of the output range[.](#tab:formatter-row-2-column-3-sentence-1)<br>The output shall only depend on t, fc.locale(), fc.arg(n) for any value n of type size_t, and the range [pc.begin(), pc.end()) from the last call to f.parse(pc)[.](#tab:formatter-row-2-column-3-sentence-2) |
| [🔗](#tab:formatter-row-3)<br>f.format(u, fc) | FC::iterator | As above, but does not modify u[.](#tab:formatter-row-3-column-3-sentence-1) |
#### [28.5.6.2](#formatter.locking) Formatter locking [[format.formatter.locking]](format.formatter.locking)
[🔗](#lib:enable_nonlocking_formatter_optimization)
`template<class T>
constexpr bool enable_nonlocking_formatter_optimization = false;
`
[1](#formatter.locking-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7086)
*Remarks*: Pursuant to [[namespace.std]](namespace.std "16.4.5.2.1Namespace std"),
users may specialize enable_nonlocking_formatter_optimization for
cv-unqualified program-defined types[.](#formatter.locking-1.sentence-1)
Such specializations shall be usable in constant expressions ([[expr.const]](expr.const "7.7Constant expressions"))
and have type const bool[.](#formatter.locking-1.sentence-2)
#### [28.5.6.3](#formattable) Concept formattable [[format.formattable]](format.formattable)
[1](#formattable-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7097)
Let *fmt-iter-for*<charT> be an unspecified type
that models[output_iterator](iterator.concept.output#concept:output_iterator "24.3.4.10Concept output_­iterator[iterator.concept.output]")<const charT&> ([[iterator.concept.output]](iterator.concept.output "24.3.4.10Concept output_­iterator"))[.](#formattable-1.sentence-1)
template<class T, class Context, class Formatter = typename Context::template formatter_type<remove_const_t<T>>>concept [*formattable-with*](#concept:formattable-with "28.5.6.3Concept formattable[format.formattable]") = // *exposition only*[semiregular](concepts.object#concept:semiregular "18.6Object concepts[concepts.object]")<Formatter> &&requires(Formatter& f, const Formatter& cf, T&& t, Context fc,
basic_format_parse_context<typename Context::char_type> pc){{ f.parse(pc) } -> [same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<typename decltype(pc)::iterator>; { cf.format(t, fc) } -> [same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<typename Context::iterator>; };
template<class T, class charT>concept [formattable](#concept:formattable "28.5.6.3Concept formattable[format.formattable]") =[*formattable-with*](#concept:formattable-with "28.5.6.3Concept formattable[format.formattable]")<remove_reference_t<T>, basic_format_context<*fmt-iter-for*<charT>, charT>>;
[2](#formattable-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7119)
A type T and a character type charT model [formattable](#concept:formattable "28.5.6.3Concept formattable[format.formattable]") if formatter<remove_cvref_t<T>, charT> meets
the *BasicFormatter* requirements ([[formatter.requirements]](#formatter.requirements "28.5.6.1Formatter requirements"))
and, if remove_reference_t<T> is const-qualified,
the *Formatter* requirements[.](#formattable-2.sentence-1)
#### [28.5.6.4](#formatter.spec) Formatter specializations [[format.formatter.spec]](format.formatter.spec)
[1](#formatter.spec-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7130)
The functions defined in [[format.functions]](#functions "28.5.5Formatting functions") use
specializations of the class template formatter to format
individual arguments[.](#formatter.spec-1.sentence-1)
[2](#formatter.spec-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7136)
Let charT be either char or wchar_t[.](#formatter.spec-2.sentence-1)
Each specialization of formatter is either enabled or disabled,
as described below[.](#formatter.spec-2.sentence-2)
A [*debug-enabled*](#def:debug-enabled "28.5.6.4Formatter specializations[format.formatter.spec]") specialization of formatter additionally provides
a public, constexpr, non-static member function set_debug_format() which modifies the state of the formatter to be as if
the type of the *std-format-spec* parsed by the last call to parse were ?[.](#formatter.spec-2.sentence-3)
Each header that declares the template formatter provides the following enabled specializations:
- [(2.1)](#formatter.spec-2.1)
The debug-enabled specializationstemplate<> struct formatter<char, char>;template<> struct formatter<char, wchar_t>;template<> struct formatter<wchar_t, wchar_t>;
- [(2.2)](#formatter.spec-2.2)
For each charT,
the debug-enabled string type specializationstemplate<> struct formatter<charT*, charT>;template<> struct formatter<const charT*, charT>;template<size_t N> struct formatter<charT[N], charT>;template<class traits, class Allocator>struct formatter<basic_string<charT, traits, Allocator>, charT>;template<class traits>struct formatter<basic_string_view<charT, traits>, charT>;
- [(2.3)](#formatter.spec-2.3)
For each charT,
for each cv-unqualified arithmetic type ArithmeticT other thanchar,wchar_t,char8_t,char16_t, orchar32_t,
a specializationtemplate<> struct formatter<ArithmeticT, charT>;
- [(2.4)](#formatter.spec-2.4)
For each charT,
the pointer type specializationstemplate<> struct formatter<nullptr_t, charT>;template<> struct formatter<void*, charT>;template<> struct formatter<const void*, charT>;
The parse member functions of these formatters
interpret the format specification
as a *std-format-spec* as described in [[format.string.std]](#string.std "28.5.2.2Standard format specifiers")[.](#formatter.spec-2.sentence-4)
[3](#formatter.spec-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7204)
Unless specified otherwise, for each type T for which
a formatter specialization is provided by the library,
each of the headers provides the following specialization:template<> inline constexpr bool enable_nonlocking_formatter_optimization<T> = true;
[*Note [1](#formatter.spec-note-1)*:
Specializations such as formatter<wchar_t, char> that would require implicit
multibyte / wide string or character conversion are disabled[.](#formatter.spec-3.sentence-1)
— *end note*]
[4](#formatter.spec-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7217)
The header <format> provides
the following disabled specializations:
- [(4.1)](#formatter.spec-4.1)
The string type specializationstemplate<> struct formatter<char*, wchar_t>;template<> struct formatter<const char*, wchar_t>;template<size_t N> struct formatter<char[N], wchar_t>;template<class traits, class Allocator>struct formatter<basic_string<char, traits, Allocator>, wchar_t>;template<class traits>struct formatter<basic_string_view<char, traits>, wchar_t>;
[5](#formatter.spec-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7234)
For any types T and charT for which
neither the library nor the user provides
an explicit or partial specialization of
the class template formatter,formatter<T, charT> is disabled[.](#formatter.spec-5.sentence-1)
[6](#formatter.spec-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7241)
If the library provides an explicit or partial specialization offormatter<T, charT>, that specialization is enabled
and meets the *Formatter* requirements
except as noted otherwise[.](#formatter.spec-6.sentence-1)
[7](#formatter.spec-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7247)
If F is a disabled specialization of formatter, these
values are false:
- [(7.1)](#formatter.spec-7.1)
is_default_constructible_v<F>,
- [(7.2)](#formatter.spec-7.2)
is_copy_constructible_v<F>,
- [(7.3)](#formatter.spec-7.3)
is_move_constructible_v<F>,
- [(7.4)](#formatter.spec-7.4)
is_copy_assignable_v<F>, and
- [(7.5)](#formatter.spec-7.5)
is_move_assignable_v<F>[.](#formatter.spec-7.sentence-1)
[8](#formatter.spec-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7258)
An enabled specialization formatter<T, charT> meets the*BasicFormatter* requirements ([[formatter.requirements]](#formatter.requirements "28.5.6.1Formatter requirements"))[.](#formatter.spec-8.sentence-1)
[*Example [1](#formatter.spec-example-1)*: #include <format>#include <string>enum color { red, green, blue };const char* color_names[] = { "red", "green", "blue" };
template<> struct std::formatter<color> : std::formatter<const char*> {auto format(color c, format_context& ctx) const {return formatter<const char*>::format(color_names[c], ctx); }};
struct err {};
std::string s0 = std::format("{}", 42); // OK, library-provided formatter std::string s1 = std::format("{}", L"foo"); // error: disabled formatter std::string s2 = std::format("{}", red); // OK, user-provided formatter std::string s3 = std::format("{}", err{}); // error: disabled formatter — *end example*]
#### [28.5.6.5](#string.escaped) Formatting escaped characters and strings [[format.string.escaped]](format.string.escaped)
[1](#string.escaped-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7286)
A character or string can be formatted as [*escaped*](#def:escaped "28.5.6.5Formatting escaped characters and strings[format.string.escaped]") to make it more suitable for debugging or for logging[.](#string.escaped-1.sentence-1)
[2](#string.escaped-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7292)
The escaped string *E* representation of a string *S* is constructed by encoding a sequence of characters as follows[.](#string.escaped-2.sentence-1)
The associated character encoding *CE* for charT (Table [12](lex.string#tab:lex.string.literal "Table 12: String literals"))
is used to both interpret *S* and construct *E*[.](#string.escaped-2.sentence-2)
- [(2.1)](#string.escaped-2.1)
U+0022 quotation mark (") is appended to *E*[.](#string.escaped-2.1.sentence-1)
- [(2.2)](#string.escaped-2.2)
For each code unit sequence *X* in *S* that either
encodes a single character,
is a shift sequence, or
is a sequence of ill-formed code units,
processing is in order as follows:
* [(2.2.1)](#string.escaped-2.2.1)
If *X* encodes a single character *C*, then:
+
[(2.2.1.1)](#string.escaped-2.2.1.1)
If *C* is one of the characters in Table [114](#tab:format.escape.sequences "Table 114: Mapping of characters to escape sequences"),
then the two characters shown as the corresponding escape sequence
are appended to *E*[.](#string.escaped-2.2.1.1.sentence-1)
+
[(2.2.1.2)](#string.escaped-2.2.1.2)
Otherwise, if *C* is not U+0020 space and
- [(2.2.1.2.1)](#string.escaped-2.2.1.2.1)
*CE* is UTF-8, UTF-16, or UTF-32 and*C* corresponds to a Unicode scalar value
whose Unicode property General_Category has a value in the groupsSeparator (Z) or Other (C),
as described by UAX #44 of the Unicode Standard, or
- [(2.2.1.2.2)](#string.escaped-2.2.1.2.2)
*CE* is UTF-8, UTF-16, or UTF-32 and*C* corresponds to a Unicode scalar value
with the Unicode property Grapheme_Extend=Yes as described by UAX #44 of the Unicode Standard and*C* is not immediately preceded in *S* by
a character *P* appended to *E* without translation to an escape sequence, or
- [(2.2.1.2.3)](#string.escaped-2.2.1.2.3)
*CE* is neither UTF-8, UTF-16, nor UTF-32 and*C* is one of an implementation-defined set
of separator or non-printable characters
then the sequence \u{*hex-digit-sequence*} is appended to *E*,
where *hex-digit-sequence* is the shortest hexadecimal representation
of *C* using lower-case hexadecimal digits[.](#string.escaped-2.2.1.2.sentence-2)
+
[(2.2.1.3)](#string.escaped-2.2.1.3)
Otherwise, *C* is appended to *E*[.](#string.escaped-2.2.1.3.sentence-1)
* [(2.2.2)](#string.escaped-2.2.2)
Otherwise, if *X* is a shift sequence,
the effect on *E* and further decoding of *S* is unspecified[.](#string.escaped-2.2.2.sentence-1)
*Recommended practice*: A shift sequence should be represented in *E* such that the original code unit sequence of *S* can be reconstructed[.](#string.escaped-2.2.2.sentence-2)
* [(2.2.3)](#string.escaped-2.2.3)
Otherwise (*X* is a sequence of ill-formed code units),
each code unit *U* is appended to *E* in order
as the sequence \x{*hex-digit-sequence*},
where *hex-digit-sequence* is the shortest hexadecimal representation of *U* using lower-case hexadecimal digits[.](#string.escaped-2.2.3.sentence-1)
- [(2.3)](#string.escaped-2.3)
Finally, U+0022 quotation mark (")
is appended to *E*[.](#string.escaped-2.3.sentence-1)
Table [114](#tab:format.escape.sequences) — Mapping of characters to escape sequences [[tab:format.escape.sequences]](./tab:format.escape.sequences)
| [🔗](#tab:format.escape.sequences-row-1)<br>**Character** | **Escape sequence** |
| --- | --- |
| [🔗](#tab:format.escape.sequences-row-2)<br>U+0009 character tabulation | \t |
| [🔗](#tab:format.escape.sequences-row-3)<br>U+000a line feed | \n |
| [🔗](#tab:format.escape.sequences-row-4)<br>U+000d carriage return | \r |
| [🔗](#tab:format.escape.sequences-row-5)<br>U+0022 quotation mark | \" |
| [🔗](#tab:format.escape.sequences-row-6)<br>U+005c reverse solidus | \\ |
[3](#string.escaped-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7404)
The escaped string representation of a character *C* is equivalent to the escaped string representation
of a string of *C*, except that:
- [(3.1)](#string.escaped-3.1)
the result starts and ends with U+0027 apostrophe (')
instead of U+0022 quotation mark ("), and
- [(3.2)](#string.escaped-3.2)
if *C* is U+0027 apostrophe,
the two characters \' are appended to *E*, and
- [(3.3)](#string.escaped-3.3)
if *C* is U+0022 quotation mark,
then *C* is appended unchanged.
[*Example [1](#string.escaped-example-1)*: string s0 = format("[{}]", "h\tllo"); // s0 has value: [h llo] string s1 = format("[{:?}]", "h\tllo"); // s1 has value: ["h\tllo"] string s2 = format("[{:?}]", "Спасибо, Виктор ♥!"); // s2 has value: ["Спасибо, Виктор ♥!"] string s3 = format("[{:?}, {:?}]", '\'', '"'); // s3 has value: ['\'', '"']// The following examples assume use of the UTF-8 encoding string s4 = format("[{:?}]", string("\0 \n \t \x02 \x1b", 9)); // s4 has value: ["\u{0} \n \t \u{2} \u{1b}"] string s5 = format("[{:?}]", "\xc3\x28"); // invalid UTF-8, s5 has value: ["\x{c3}("] string s6 = format("[{:?}]", "🤷🏻‍♂️"); // s6 has value: ["🤷\u{200d}♂"] string s7 = format("[{:?}]", "\u0301"); // s7 has value: ["\u{301}"] string s8 = format("[{:?}]", "\\\u0301"); // s8 has value: ["\\\u{301}"] string s9 = format("[{:?}]", "e\u0301\u0323"); // s9 has value: ["ẹ́"] — *end example*]
#### [28.5.6.6](#parse.ctx) Class template basic_format_parse_context [[format.parse.ctx]](format.parse.ctx)
[🔗](#lib:basic_format_parse_context)
namespace std {template<class charT>class basic_format_parse_context {public:using char_type = charT; using const_iterator = typename basic_string_view<charT>::const_iterator; using iterator = const_iterator; private: iterator begin_; // *exposition only* iterator end_; // *exposition only*enum indexing { unknown, manual, automatic }; // *exposition only* indexing indexing_; // *exposition only* size_t next_arg_id_; // *exposition only* size_t num_args_; // *exposition only*public:constexpr explicit basic_format_parse_context(basic_string_view<charT> fmt) noexcept;
basic_format_parse_context(const basic_format_parse_context&) = delete;
basic_format_parse_context& operator=(const basic_format_parse_context&) = delete; constexpr const_iterator begin() const noexcept; constexpr const_iterator end() const noexcept; constexpr void advance_to(const_iterator it); constexpr size_t next_arg_id(); constexpr void check_arg_id(size_t id); template<class... Ts>constexpr void check_dynamic_spec(size_t id) noexcept; constexpr void check_dynamic_spec_integral(size_t id) noexcept; constexpr void check_dynamic_spec_string(size_t id) noexcept; };}
[1](#parse.ctx-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7482)
An instance of basic_format_parse_context holds
the format string parsing state, consisting of
the format string range being parsed and
the argument counter for automatic indexing[.](#parse.ctx-1.sentence-1)
[2](#parse.ctx-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7488)
If a program declares an explicit or partial specialization ofbasic_format_parse_context,
the program is ill-formed, no diagnostic required[.](#parse.ctx-2.sentence-1)
[🔗](#lib:basic_format_parse_context,constructor)
`constexpr explicit basic_format_parse_context(basic_string_view<charT> fmt) noexcept;
`
[3](#parse.ctx-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7499)
*Effects*: Initializesbegin_ with fmt.begin(),end_ with fmt.end(),indexing_ with unknown,next_arg_id_ with 0, andnum_args_ with 0[.](#parse.ctx-3.sentence-1)
[*Note [1](#parse.ctx-note-1)*:
Any call tonext_arg_id, check_arg_id, or check_dynamic_spec on an instance of basic_format_parse_context initialized using this constructor is not a core constant expression[.](#parse.ctx-3.sentence-2)
— *end note*]
[🔗](#lib:begin,basic_format_parse_context)
`constexpr const_iterator begin() const noexcept;
`
[4](#parse.ctx-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7521)
*Returns*: begin_[.](#parse.ctx-4.sentence-1)
[🔗](#lib:end,basic_format_parse_context)
`constexpr const_iterator end() const noexcept;
`
[5](#parse.ctx-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7532)
*Returns*: end_[.](#parse.ctx-5.sentence-1)
[🔗](#lib:advance_to,basic_format_parse_context)
`constexpr void advance_to(const_iterator it);
`
[6](#parse.ctx-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7543)
*Preconditions*: end() is reachable from it[.](#parse.ctx-6.sentence-1)
[7](#parse.ctx-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7547)
*Effects*: Equivalent to: begin_ = it;
[🔗](#lib:next_arg_id,basic_format_parse_context)
`constexpr size_t next_arg_id();
`
[8](#parse.ctx-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7558)
*Effects*: If indexing_ != manual is true, equivalent to:if (indexing_ == unknown) indexing_ = automatic;return next_arg_id_++;
[9](#parse.ctx-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7567)
*Throws*: format_error if indexing_ == manual is true[.](#parse.ctx-9.sentence-1)
[*Note [2](#parse.ctx-note-2)*:
This indicates mixing of automatic and manual argument indexing[.](#parse.ctx-9.sentence-2)
— *end note*]
[10](#parse.ctx-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7574)
*Remarks*: Let *cur-arg-id* be the value of next_arg_id_ prior to this call[.](#parse.ctx-10.sentence-1)
Call expressions where *cur-arg-id* >= num_args_ is true are not core constant expressions ([[expr.const]](expr.const "7.7Constant expressions"))[.](#parse.ctx-10.sentence-2)
[🔗](#lib:check_arg_id,basic_format_parse_context)
`constexpr void check_arg_id(size_t id);
`
[11](#parse.ctx-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7587)
*Effects*: If indexing_ != automatic is true, equivalent to:if (indexing_ == unknown) indexing_ = manual;
[12](#parse.ctx-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7595)
*Throws*: format_error ifindexing_ == automatic is true[.](#parse.ctx-12.sentence-1)
[*Note [3](#parse.ctx-note-3)*:
This indicates mixing of automatic and manual argument indexing[.](#parse.ctx-12.sentence-2)
— *end note*]
[13](#parse.ctx-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7603)
*Remarks*: A call to this function is a core constant expression ([[expr.const]](expr.const "7.7Constant expressions")) only ifid < num_args_ is true[.](#parse.ctx-13.sentence-1)
[🔗](#lib:check_dynamic_spec,basic_format_parse_context)
`template<class... Ts>
constexpr void check_dynamic_spec(size_t id) noexcept;
`
[14](#parse.ctx-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7616)
*Mandates*: sizeof...(Ts) ≥ 1[.](#parse.ctx-14.sentence-1)
The types in Ts... are unique[.](#parse.ctx-14.sentence-2)
Each type in Ts... is one ofbool,char_type,int,unsigned int,long long int,unsigned long long int,float,double,long double,const char_type*,basic_string_view<char_type>, orconst void*[.](#parse.ctx-14.sentence-3)
[15](#parse.ctx-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7634)
*Remarks*: A call to this function is a core constant expression only if
- [(15.1)](#parse.ctx-15.1)
id < num_args_ is true and
- [(15.2)](#parse.ctx-15.2)
the type of the corresponding format argument
(after conversion to basic_format_arg<Context>) is one of the types in Ts...[.](#parse.ctx-15.sentence-1)
[🔗](#lib:check_dynamic_spec_integral,basic_format_parse_context)
`constexpr void check_dynamic_spec_integral(size_t id) noexcept;
`
[16](#parse.ctx-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7652)
*Effects*: Equivalent to:check_dynamic_spec<int, unsigned int, long long int, unsigned long long int>(id);
[🔗](#lib:check_dynamic_spec_string,basic_format_parse_context)
`constexpr void check_dynamic_spec_string(size_t id) noexcept;
`
[17](#parse.ctx-17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7666)
*Effects*: Equivalent to:check_dynamic_spec<const char_type*, basic_string_view<char_type>>(id);
#### [28.5.6.7](#context) Class template basic_format_context [[format.context]](format.context)
[🔗](#lib:basic_format_context)
namespace std {template<class Out, class charT>class basic_format_context { basic_format_args<basic_format_context> args_; // *exposition only* Out out_; // *exposition only* basic_format_context(const basic_format_context&) = delete;
basic_format_context& operator=(const basic_format_context&) = delete; public:using iterator = Out; using char_type = charT; template<class T> using formatter_type = formatter<T, charT>;
basic_format_arg<basic_format_context> arg(size_t id) const noexcept;
std::locale locale();
iterator out(); void advance_to(iterator it); };}
[1](#context-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7704)
An instance of basic_format_context holds formatting state
consisting of the formatting arguments and the output iterator[.](#context-1.sentence-1)
[2](#context-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7708)
If a program declares an explicit or partial specialization ofbasic_format_context,
the program is ill-formed, no diagnostic required[.](#context-2.sentence-1)
[3](#context-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7713)
Out shall model [output_iterator](iterator.concept.output#concept:output_iterator "24.3.4.10Concept output_­iterator[iterator.concept.output]")<const charT&>[.](#context-3.sentence-1)
[4](#context-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7716)
format_context is an alias for
a specialization of basic_format_context with an output iterator
that appends to string,
such as back_insert_iterator<string>[.](#context-4.sentence-1)
Similarly, wformat_context is an alias for
a specialization of basic_format_context with an output iterator
that appends to wstring[.](#context-4.sentence-2)
[5](#context-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7729)
*Recommended practice*: For a given type charT,
implementations should provide
a single instantiation of basic_format_context for appending tobasic_string<charT>,vector<charT>,
or any other container with contiguous storage
by wrapping those in temporary objects with a uniform interface
(such as a span<charT>) and polymorphic reallocation[.](#context-5.sentence-1)
[🔗](#lib:arg,basic_format_context)
`basic_format_arg<basic_format_context> arg(size_t id) const noexcept;
`
[6](#context-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7747)
*Returns*: args_.get(id)[.](#context-6.sentence-1)
[🔗](#lib:locale,basic_format_context)
`std::locale locale();
`
[7](#context-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7758)
*Returns*: The locale passed to the formatting function
if the latter takes one,
and std::locale() otherwise[.](#context-7.sentence-1)
[🔗](#lib:out,basic_format_context)
`iterator out();
`
[8](#context-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7771)
*Effects*: Equivalent to: return std::move(out_);
[🔗](#lib:advance_to,basic_format_context)
`void advance_to(iterator it);
`
[9](#context-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7782)
*Effects*: Equivalent to: out_ = std::move(it);
[*Example [1](#context-example-1)*: struct S { int value; };
template<> struct std::formatter<S> { size_t width_arg_id = 0; // Parses a width argument id in the format { *digit* }.constexpr auto parse(format_parse_context& ctx) {auto iter = ctx.begin(); auto is_digit = [](auto c) { return c >= '0' && c <= '9'; }; auto get_char = [&]() { return iter != ctx.end() ? *iter : 0; }; if (get_char() != '{')return iter; ++iter; char c = get_char(); if (!is_digit(c) || (++iter, get_char()) != '}')throw format_error("invalid format");
width_arg_id = c - '0';
ctx.check_arg_id(width_arg_id); return ++iter; }// Formats an S with width given by the argument width_arg_id.auto format(S s, format_context& ctx) const {int width = ctx.arg(width_arg_id).visit([](auto value) -> int {if constexpr (!is_integral_v<decltype(value)>)throw format_error("width is not integral"); else if (value < 0 || value > numeric_limits<int>::max())throw format_error("invalid width"); elsereturn value; }); return format_to(ctx.out(), "{0:x>{1}}", s.value, width); }};
std::string s = std::format("{0:{1}}", S{42}, 10); // value of s is "xxxxxxxx42" — *end example*]
### [28.5.7](#range) Formatting of ranges [[format.range]](format.range)
#### [28.5.7.1](#range.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](#range.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[.](#range.fmtkind-1.sentence-1)
[2](#range.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)](#range.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[.](#range.fmtkind-2.1.sentence-1)
[*Note [1](#range.fmtkind-note-1)*:
This prevents constraint recursion for ranges whose
reference type is the same range type[.](#range.fmtkind-2.1.sentence-2)
For example,std::filesystem::path is a range of std::filesystem::path[.](#range.fmtkind-2.1.sentence-3)
— *end note*]
- [(2.2)](#range.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)](#range.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>>[.](#range.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[.](#range.fmtkind-2.2.1.sentence-2)
* [(2.2.2)](#range.fmtkind-2.2.2)
Otherwise, format_kind<R> is range_format::set[.](#range.fmtkind-2.2.2.sentence-1)
- [(2.3)](#range.fmtkind-2.3)
Otherwise, format_kind<R> is range_format::sequence[.](#range.fmtkind-2.3.sentence-1)
[3](#range.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]")[.](#range.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[.](#range.fmtkind-3.sentence-2)
#### [28.5.7.2](#range.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](#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](#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](#range.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[.](#range.formatter-1.sentence-1)
[2](#range.formatter-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L7925)
range_formatter interprets *format-spec* as a *range-format-spec*[.](#range.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](#range.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>[.](#range.formatter-3.sentence-1)
[4](#range.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]](#string.std "28.5.2.2Standard format specifiers"))[.](#range.formatter-4.sentence-1)
The productions *align* and *width* are described in [[format.string]](#string "28.5.2Format string")[.](#range.formatter-4.sentence-2)
[5](#range.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[.](#range.formatter-5.sentence-1)
[*Note [1](#range.formatter-note-1)*:
This is equivalent to invoking set_brackets({}, {})[.](#range.formatter-5.sentence-2)
— *end note*]
[6](#range.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[.](#range.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")[.](#range.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]](#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*[.](#range.formatter-6.sentence-3)
[🔗](#lib:set_separator,range_formatter)
`constexpr void set_separator(basic_string_view<charT> sep) noexcept;
`
[7](#range.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](#range.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](#range.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[.](#range.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*[.](#range.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[.](#range.formatter-9.sentence-3)
If:
- [(9.1)](#range.formatter-9.1)
the *range-type* is neither s nor ?s,
- [(9.2)](#range.formatter-9.2)
*underlying_*.set_debug_format() is a valid expression, and
- [(9.3)](#range.formatter-9.3)
there is no *range-underlying-spec*,
then calls *underlying_*.set_debug_format()[.](#range.formatter-9.sentence-4)
[10](#range.formatter-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8076)
*Returns*: An iterator past the end of the *range-format-spec*[.](#range.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](#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](#range.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)](#range.formatter-11.1)
If the *range-type* was s,
then as if by formatting basic_string<charT>(from_range, r)[.](#range.formatter-11.1.sentence-1)
- [(11.2)](#range.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]](#string.escaped "28.5.6.5Formatting escaped characters and strings"))[.](#range.formatter-11.2.sentence-1)
- [(11.3)](#range.formatter-11.3)
Otherwise,
* [(11.3.1)](#range.formatter-11.3.1)
*opening-bracket_*,
* [(11.3.2)](#range.formatter-11.3.2)
for each element e of the range r:
+
[(11.3.2.1)](#range.formatter-11.3.2.1)
the result of writing e via *underlying_* and
+
[(11.3.2.2)](#range.formatter-11.3.2.2)
*separator_*, unless e is the last element of r, and
* [(11.3.3)](#range.formatter-11.3.3)
*closing-bracket_*[.](#range.formatter-11.3.sentence-1)
[12](#range.formatter-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8122)
*Returns*: An iterator past the end of the output range[.](#range.formatter-12.sentence-1)
#### [28.5.7.3](#range.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](#range.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](#range.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](#range.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](#range.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](#range.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](#range.fmtmap-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8237)
*Mandates*: Either:
- [(1.1)](#range.fmtmap-1.1)
*element-type* is a specialization of pair, or
- [(1.2)](#range.fmtmap-1.2)
*element-type* is a specialization of tuple andtuple_size_v<*element-type*> == 2[.](#range.fmtmap-1.sentence-1)
[2](#range.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](#range.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](#range.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](#range.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](#range.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](#range.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](#range.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](#range.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](#range.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[.](#range.fmtstr-1.sentence-1)
[🔗](#lib:parse,range-default-formatter___)
`template<class ParseContext>
constexpr typename ParseContext::iterator
parse(ParseContext& ctx);
`
[2](#range.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](#range.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[.](#range.fmtstr-3.sentence-1)
[4](#range.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[.](#range.fmtstr-4.sentence-1)
Equivalent to: return *underlying_*.format(*s*, ctx);
### [28.5.8](#arguments) Arguments [[format.arguments]](format.arguments)
#### [28.5.8.1](#arg) Class template basic_format_arg [[format.arg]](format.arg)
[🔗](#lib:basic_format_arg)
namespace std {template<class Context>class basic_format_arg {public:class handle; private:using char_type = typename Context::char_type; // *exposition only* variant<monostate, bool, char_type, int, unsigned int, long long int, unsigned long long int, float, double, long double, const char_type*, basic_string_view<char_type>, const void*, handle> value; // *exposition only*template<class T> explicit basic_format_arg(T& v) noexcept; // *exposition only*public: basic_format_arg() noexcept; explicit operator bool() const noexcept; template<class Visitor>decltype(auto) visit(this basic_format_arg arg, Visitor&& vis); template<class R, class Visitor> R visit(this basic_format_arg arg, Visitor&& vis); };}
[1](#arg-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8454)
An instance of basic_format_arg provides access to
a formatting argument for user-defined formatters[.](#arg-1.sentence-1)
[2](#arg-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8458)
The behavior of a program that adds specializations ofbasic_format_arg is undefined[.](#arg-2.sentence-1)
[🔗](#lib:basic_format_arg,constructor)
`basic_format_arg() noexcept;
`
[3](#arg-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8468)
*Postconditions*: !(*this)[.](#arg-3.sentence-1)
[🔗](#arg-itemdecl:2)
`template<class T> explicit basic_format_arg(T& v) noexcept;
`
[4](#arg-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8478)
*Constraints*: T satisfies [*formattable-with*](#concept:formattable-with "28.5.6.3Concept formattable[format.formattable]")<Context>[.](#arg-4.sentence-1)
[5](#arg-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8482)
*Preconditions*: If decay_t<T> is char_type* or const char_type*,static_cast<const char_
type*>(v) points to an NTCTS ([[defns.ntcts]](defns.ntcts "3.36NTCTS"))[.](#arg-5.sentence-1)
[6](#arg-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8487)
*Effects*: Let TD be remove_const_t<T>[.](#arg-6.sentence-1)
- [(6.1)](#arg-6.1)
If TD is bool or char_type,
initializes value with v;
- [(6.2)](#arg-6.2)
otherwise, if TD is char and char_type iswchar_t, initializes value withstatic_cast<wchar_t>(static_cast<unsigned char>(v));
- [(6.3)](#arg-6.3)
otherwise, if TD is a signed integer type ([[basic.fundamental]](basic.fundamental "6.9.2Fundamental types"))
and sizeof(TD) <= sizeof(int),
initializes value with static_cast<int>(v);
- [(6.4)](#arg-6.4)
otherwise, if TD is an unsigned integer type andsizeof(TD) <= sizeof(unsigned int), initializesvalue with static_cast<unsigned int>(v);
- [(6.5)](#arg-6.5)
otherwise, if TD is a signed integer type andsizeof(TD) <= sizeof(long long int), initializesvalue with static_cast<long long int>(v);
- [(6.6)](#arg-6.6)
otherwise, if TD is an unsigned integer type andsizeof(TD) <= sizeof(unsigned long long int), initializesvalue withstatic_cast<unsigned long long int>(v);
- [(6.7)](#arg-6.7)
otherwise, if TD is a standard floating-point type,
initializes value with v;
- [(6.8)](#arg-6.8)
otherwise, if TD is
a specialization of basic_string_view or basic_string andTD::value_type is char_type,
initializes value withbasic_string_view<char_type>(v.data(), v.size());
- [(6.9)](#arg-6.9)
otherwise, if decay_t<TD> ischar_type* or const char_type*,
initializes value with static_cast<const char_type*>(v);
- [(6.10)](#arg-6.10)
otherwise, if is_void_v<remove_pointer_t<TD>> is true oris_null_pointer_v<TD> is true,
initializes value with static_cast<const void*>(v);
- [(6.11)](#arg-6.11)
otherwise, initializes value with handle(v).
[*Note [1](#arg-note-1)*:
Constructing basic_format_arg from a pointer to a member is ill-formed
unless the user provides an enabled specialization of formatter for that pointer to member type[.](#arg-6.sentence-2)
— *end note*]
[🔗](#lib:operator_bool,basic_format_arg)
`explicit operator bool() const noexcept;
`
[7](#arg-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8550)
*Returns*: !holds_alternative<monostate>(value)[.](#arg-7.sentence-1)
[🔗](#lib:visit,basic_format_arg)
`template<class Visitor>
decltype(auto) visit(this basic_format_arg arg, Visitor&& vis);
`
[8](#arg-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8562)
*Effects*: Equivalent to: return arg.value.visit(std::forward<Visitor>(vis));
[🔗](#lib:visit,basic_format_arg_)
`template<class R, class Visitor>
R visit(this basic_format_arg arg, Visitor&& vis);
`
[9](#arg-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8574)
*Effects*: Equivalent to: return arg.value.visit<R>(std::forward<Visitor>(vis));
[10](#arg-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8579)
The class handle allows formatting an object of a user-defined type[.](#arg-10.sentence-1)
[🔗](#lib:basic_format_arg::handle)
namespace std {template<class Context>class basic_format_arg<Context>::handle {const void* ptr_; // *exposition only*void (*format_)(basic_format_parse_context<char_type>&,
Context&, const void*); // *exposition only*template<class T> explicit handle(T& val) noexcept; // *exposition only*public:void format(basic_format_parse_context<char_type>&, Context& ctx) const; };}
[🔗](#lib:basic_format_arg::handle,constructor)
`template<class T> explicit handle(T& val) noexcept;
`
[11](#arg-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8606)
Let
- [(11.1)](#arg-11.1)
TD be remove_const_t<T>,
- [(11.2)](#arg-11.2)
TQ be const TD ifconst TD satisfies [*formattable-with*](#concept:formattable-with "28.5.6.3Concept formattable[format.formattable]")<Context> and TD otherwise[.](#arg-11.sentence-1)
[12](#arg-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8617)
*Mandates*: TQ satisfies [*formattable-with*](#concept:formattable-with "28.5.6.3Concept formattable[format.formattable]")<Context>[.](#arg-12.sentence-1)
[13](#arg-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8621)
*Effects*: Initializesptr_ with addressof(val) andformat_ with[](basic_format_parse_context<char_type>& parse_ctx,
Context& format_ctx, const void* ptr) {typename Context::template formatter_type<TD> f;
parse_ctx.advance_to(f.parse(parse_ctx));
format_ctx.advance_to(f.format(*const_cast<TQ*>(static_cast<const TD*>(ptr)),
format_ctx));}
[🔗](#lib:format,basic_format_arg::handle)
`void format(basic_format_parse_context<char_type>& parse_ctx, Context& format_ctx) const;
`
[14](#arg-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8643)
*Effects*: Equivalent to: format_(parse_ctx, format_ctx, ptr_);
#### [28.5.8.2](#arg.store) Class template *format-arg-store* [[format.arg.store]](format.arg.store)
namespace std {template<class Context, class... Args>class *format-arg-store* { // *exposition only* array<basic_format_arg<Context>, sizeof...(Args)> *args*; // *exposition only*};}
[1](#arg.store-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8659)
An instance of *format-arg-store* stores formatting arguments[.](#arg.store-1.sentence-1)
[🔗](#lib:make_format_args)
`template<class Context = format_context, class... Args>
format-arg-store<Context, Args...> make_format_args(Args&... fmt_args);
`
[2](#arg.store-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8669)
*Preconditions*: The typetypename Context::template formatter_type<remove_const_t<Ti>>
meets the *BasicFormatter* requirements ([[formatter.requirements]](#formatter.requirements "28.5.6.1Formatter requirements"))
for each Ti in Args[.](#arg.store-2.sentence-1)
[3](#arg.store-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8676)
*Returns*: An object of type *format-arg-store*<Context, Args...> whose *args* data member is initialized with{basic_format_arg<Context>(fmt_args)...}[.](#arg.store-3.sentence-1)
[🔗](#lib:make_wformat_args)
`template<class... Args>
format-arg-store<wformat_context, Args...> make_wformat_args(Args&... args);
`
[4](#arg.store-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8690)
*Effects*: Equivalent to:return make_format_args<wformat_context>(args...);
#### [28.5.8.3](#args) Class template basic_format_args [[format.args]](format.args)
namespace std {template<class Context>class basic_format_args { size_t size_; // *exposition only*const basic_format_arg<Context>* data_; // *exposition only*public:template<class... Args> basic_format_args(const *format-arg-store*<Context, Args...>& store) noexcept;
basic_format_arg<Context> get(size_t i) const noexcept; }; template<class Context, class... Args> basic_format_args(*format-arg-store*<Context, Args...>) -> basic_format_args<Context>;}
[1](#args-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8717)
An instance of basic_format_args provides access to formatting
arguments[.](#args-1.sentence-1)
Implementations should
optimize the representation of basic_format_args for a small number of formatting arguments[.](#args-1.sentence-2)
[*Note [1](#args-note-1)*:
For example, by storing indices of type alternatives separately from values
and packing the former[.](#args-1.sentence-3)
— *end note*]
[🔗](#lib:basic_format_args,constructor)
`template<class... Args>
basic_format_args(const format-arg-store<Context, Args...>& store) noexcept;
`
[2](#args-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8735)
*Effects*: Initializessize_ with sizeof...(Args) anddata_ with store.args.data()[.](#args-2.sentence-1)
[🔗](#lib:get,basic_format_args)
`basic_format_arg<Context> get(size_t i) const noexcept;
`
[3](#args-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8748)
*Returns*: i < size_ ? data_[i] : basic_format_arg<Context>()[.](#args-3.sentence-1)
### [28.5.9](#tuple) Tuple formatter [[format.tuple]](format.tuple)
[1](#tuple-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8755)
For each of pair and tuple,
the library provides the following formatter specialization
where *pair-or-tuple* is the name of the template:
[🔗](#lib:formatter_)
namespace std {template<class charT, [formattable](#concept:formattable "28.5.6.3Concept formattable[format.formattable]")<charT>... Ts>struct formatter<*pair-or-tuple*<Ts...>, charT> {private: tuple<formatter<remove_cvref_t<Ts>, 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; template<class ParseContext>constexpr typename ParseContext::iterator
parse(ParseContext& ctx); template<class FormatContext>typename FormatContext::iterator
format(*see below*& elems, FormatContext& ctx) const; }; template<class... Ts>constexpr bool enable_nonlocking_formatter_optimization<*pair-or-tuple*<Ts...>> =(enable_nonlocking_formatter_optimization<Ts> && ...);}
[2](#tuple-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8791)
The parse member functions of these formatters
interpret the format specification as
a *tuple-format-spec* according to the following syntax:
tuple-format-spec :
tuple-fill-and-alignopt widthopt tuple-typeopt
tuple-fill-and-align :
tuple-fillopt align
tuple-fill :
any character other than { or } or :
tuple-type :
m
n
[3](#tuple-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8817)
The *tuple-fill-and-align* is interpreted the same way as
a *fill-and-align* ([[format.string.std]](#string.std "28.5.2.2Standard format specifiers"))[.](#tuple-3.sentence-1)
The productions *align* and *width* are described in [[format.string]](#string "28.5.2Format string")[.](#tuple-3.sentence-2)
[4](#tuple-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8823)
The *tuple-type* specifier
changes the way a pair or tuple is formatted,
with certain options only valid with certain argument types[.](#tuple-4.sentence-1)
The meaning of the various type options
is as specified in Table [116](#tab:formatter.tuple.type "Table 116: Meaning of tuple-type options")[.](#tuple-4.sentence-2)
Table [116](#tab:formatter.tuple.type) — Meaning of *tuple-type* options [[tab:formatter.tuple.type]](./tab:formatter.tuple.type)
| [🔗](#tab:formatter.tuple.type-row-1)<br>**Option** | **Requirements** | **Meaning** |
| --- | --- | --- |
| [🔗](#tab:formatter.tuple.type-row-2)<br>m | sizeof...(Ts) == 2 | Equivalent to: set_separator(*STATICALLY-WIDEN*<charT>(": ")); set_brackets({}, {}); |
| [🔗](#tab:formatter.tuple.type-row-3)<br>n | none | Equivalent to: set_brackets({}, {}); |
| [🔗](#tab:formatter.tuple.type-row-4)<br>none | none | No effects |
[🔗](#lib:set_separator,formatter)
`constexpr void set_separator(basic_string_view<charT> sep) noexcept;
`
[5](#tuple-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8861)
*Effects*: Equivalent to: *separator_* = sep;
[🔗](#lib:set_brackets,formatter)
`constexpr void set_brackets(basic_string_view<charT> opening,
basic_string_view<charT> closing) noexcept;
`
[6](#tuple-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8873)
*Effects*: Equivalent to:*opening-bracket_* = opening;*closing-bracket_* = closing;
[🔗](#lib:parse,formatter)
`template<class ParseContext>
constexpr typename ParseContext::iterator
parse(ParseContext& ctx);
`
[7](#tuple-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8890)
*Effects*: Parses the format specifiers as a *tuple-format-spec* and
stores the parsed specifiers in *this[.](#tuple-7.sentence-1)
The values of*opening-bracket_*,*closing-bracket_*, and*separator_* are modified if and only if
required by the *tuple-type*, if present[.](#tuple-7.sentence-2)
For each element *e* in *underlying_*,
calls *e*.parse(ctx) to parse
an empty *format-spec* and,
if *e*.set_debug_format() is a valid expression,
calls *e*.set_debug_format()[.](#tuple-7.sentence-3)
[8](#tuple-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8906)
*Returns*: An iterator past the end of the *tuple-format-spec*[.](#tuple-8.sentence-1)
[🔗](#lib:format,formatter)
`template<class FormatContext>
typename FormatContext::iterator
format(see below& elems, FormatContext& ctx) const;
`
[9](#tuple-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8919)
The type of elems is:
- [(9.1)](#tuple-9.1)
If ([formattable](#concept:formattable "28.5.6.3Concept formattable[format.formattable]")<const Ts, charT> && ...) is true,const *pair-or-tuple*<Ts...>&[.](#tuple-9.1.sentence-1)
- [(9.2)](#tuple-9.2)
Otherwise *pair-or-tuple*<Ts...>&[.](#tuple-9.2.sentence-1)
[10](#tuple-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8929)
*Effects*: Writes the following into ctx.out(),
adjusted according to the *tuple-format-spec*:
- [(10.1)](#tuple-10.1)
*opening-bracket_*,
- [(10.2)](#tuple-10.2)
for each index I in the [0, sizeof...(Ts)):
* [(10.2.1)](#tuple-10.2.1)
if I != 0, *separator_*,
* [(10.2.2)](#tuple-10.2.2)
the result of writing get<I>(elems) via get<I>(*underlying_*), and
- [(10.3)](#tuple-10.3)
*closing-bracket_*[.](#tuple-10.sentence-1)
[11](#tuple-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8949)
*Returns*: An iterator past the end of the output range[.](#tuple-11.sentence-1)
### [28.5.10](#error) Class format_error [[format.error]](format.error)
[🔗](#lib:format_error)
namespace std {class format_error : public runtime_error {public:constexpr explicit format_error(const string& what_arg); constexpr explicit format_error(const char* what_arg); };}
[1](#error-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8967)
The class format_error defines the type of objects thrown as
exceptions to report errors from the formatting library[.](#error-1.sentence-1)
[🔗](#lib:format_error,constructor)
`constexpr format_error(const string& what_arg);
`
[2](#error-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8977)
*Postconditions*: strcmp(what(), what_arg.c_str()) == 0[.](#error-2.sentence-1)
[🔗](#error-itemdecl:2)
`constexpr format_error(const char* what_arg);
`
[3](#error-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/text.tex#L8988)
*Postconditions*: strcmp(what(), what_arg) == 0[.](#error-3.sentence-1)