Text Formatting

Changes since R9

Rebase wording onto the pre-Cologne C++ working draft N4820, in particular updating the section number from 19 to 20.

Change "A format string is a possibly empty sequence of zero or more" to "A format string is a (possibly empty) sequence of" in [format.string].

Replace "digit separator characters including the decimal radix separator" with "digit group separator characters" in the integer presentation types table in [format.string] since decimal radix separator doesn't apply to integer types.

Replace "digit separator characters including the decimal radix separator" with "digit group and decimal radix separator characters" in the floating-point presentation types table in [format.string] to clarify what separator characters are.

Replace "satisfies the OutputIterator<const charT&> requirements" with "satisfies OutputIterator<const charT&> " per Specification Style Guidelines.

requirements" with "satisfies " per Specification Style Guidelines. Clarify the semantics of operator + in [format.functions].

in [format.functions]. Replace Mandates with a precondition that formatter<T i , charT> meets the Formatter requirements in format_to_n , formatted_size , and make_format_args . Other functions get this precondition transitively via make_format_args .

with a precondition that meets the requirements in , , and . Other functions get this precondition transitively via . Replace "will meet the Formatter requirements" with "meets the Formatter requirements" in [format.formatter].

requirements" with "meets the requirements" in [format.formatter]. Merge the precondition into Remarks getting rid of the unorthodox use of is_constant_evaluated in basic_format_parse_context::check_arg_id .

getting rid of the unorthodox use of in . Clarify how an implementation determines if typename Context::template formatter_type<T> is enabled in basic_format_arg .

is enabled in . Replace "Let charT be decltype(fmt)::value_type ." with "Let charT be the character type of the format string." and move it to the first paragraph of [format.string].

be ." with "Let be the character type of the format string." and move it to the first paragraph of [format.string]. Change three occurrences of the construct of the form "A if B, C otherwise" with "if B, A; otherwise, C" in the floating-point and pointer presentation tables [format.string] for readability.

Add "unless specified otherwise" after "Formatting of objects of arithmetic types and const void* is done as if by calling to_chars " in [format.string] because infinity and NaN do not delegate to to_chars .

is done as if by calling " in [format.string] because infinity and NaN do not delegate to . Clarify that infinity and NaN are formatted as "inf" and "nan" for lower-case presentation types and "INF" and "NAN" for upper-case ones in [format.string].

and for lower-case presentation types and and for upper-case ones in [format.string]. Replace " Out models OutputIterator<const charT&> . formatter " with " Out models OutputIterator<const charT&> , and formatter " in format_to_n to avoid potential confusion that formatter is a member.

Changes since R8

Changes since R7

Changes since R6

Rebase wording onto the pre-Kona C++ working draft N4800.

Use placeholder for section and table numbers and drop "utilities" from the section name.

Clarify the parse wording in Table � — Formatter requirements.

wording in Table � — Formatter requirements. Add an entry to the "General utilities library summary" table.

Replace overload resolution Remarks with Constraints per p1369.

with per p1369. Remove "shall" from Expects wording.

wording. Add Kona LEWG poll results for R6.

Minor improvements to the wording and editing notes.

Changes since R5

Separate parsing context from formatting context and remove basic_format_context::parse_context() .

. Require that id in basic_format_parse_context::check_arg_id is a valid argument id.

in is a valid argument id. Replace Requires with Expects per p1369.

Show only wording and recent revision history

LEWG polls (R6):

basic_format_context<>::parse_context()

SF F N A SA 7 2 0 0 0

Remove

Unanimous consent to all other design changes presented.

SF F N A SA 8 4 0 0 0

Forward back to LWG as written for C++20.

All wording is relative to the pre-Cologne C++ working draft N4820.

The � character is used to denote a placeholder section number, table number, or paragraph number which the editor shall determine.

Add the header <format> to the "C++ library headers" table in [headers], in a place that respects the table’s current alphabetic order.

Add an entry for __cpp_lib_format to the "Standard library feature-test macros" table in [support.limits.general], in a place that respects the table’s current alphabetic order:

Macro name Value Header(s) … … … __cpp_lib_format 201902L ** placeholder ** <format> … … …

Add a new entry to the "General utilities library summary" table in [utilities.general]:

Subclause Header(s) … … 20.19 Primitive numeric conversions <charconv> 20.� Formatting <format>

Add a new section in 20 [utilities].

namespace std { // [format.error], class format_error class format_error; // [format.formatter], formatter template<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>; template<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>; template<class T, class charT = char> struct formatter; // [format.arguments], arguments template<class Context> class basic_format_arg; template<class Visitor, class Context> see below visit_format_arg(Visitor&& vis, basic_format_arg<Context> arg); template<class Context, class... Args> struct format-arg-store; // exposition only template<class Context> class basic_format_args; using format_args = basic_format_args<format_context>; using wformat_args = basic_format_args<wformat_context>; template<class Out, class charT> using format_args_t = basic_format_args<basic_format_context<Out, charT>>; template<class Context = format_context, class... Args> format-arg-store<Context, Args...> make_format_args(const Args&... args); template<class... Args> format-arg-store<wformat_context, Args...> make_wformat_args(const Args&... args); // [format.functions], formatting functions template<class... Args> string format(string_view fmt, const Args&... args); template<class... Args> wstring format(wstring_view fmt, const Args&... args); string vformat(string_view fmt, format_args args); wstring vformat(wstring_view fmt, wformat_args args); template<class Out, class... Args> Out format_to(Out out, string_view fmt, const Args&... args); template<class Out, class... Args> Out format_to(Out out, wstring_view fmt, const Args&... args); template<class Out> Out vformat_to(Out out, string_view fmt, format_args_t<Out, char> args); template<class Out> Out vformat_to(Out out, wstring_view fmt, format_args_t<Out, wchar_t> 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, string_view fmt, const Args&... args); template<class Out, class... Args> format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n, wstring_view fmt, const Args&... args); template<class... Args> size_t formatted_size(string_view fmt, const Args&... args); template<class... Args> size_t formatted_size(wstring_view fmt, const Args&... args); }

A format string is a (possibly empty) sequence of replacement fields, escape sequences, and other characters. Let charT be the character type of the format string. Each character that is not part of a replacement field or an escape sequence is copied unchanged to the output. An escape sequence is one of {{ or }} . It is replaced with { or } respectively in the output. The syntax of replacement fields is as follows:

replacement-field ::= '{' [arg-id] [':' format-spec] '}' arg-id ::= '0' | nonzero-digit [integer] integer ::= digit [integer] nonzero-digit ::= '1'...'9' digit ::= '0'...'9'

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. The optional format-spec field specifies a non-default format for the replacement value.

string s = format("{0}-{{", 8); // s == "8-{"

If the numeric arg-id s in a format string are 0, 1, 2, ... in sequence, they can all be omitted (not just some) and the numbers 0, 1, 2, ... will be automatically used in that order. A format string does not contain a mixture of automatic and manual indexing.

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"); // Error: mixing automatic and manual indexing string s3 = format("{} to {1}", "a", "b"); // Error: mixing automatic and manual indexing

The format-spec field contains format specifications that define how the value should be presented, including such details as field width, alignment, padding, and decimal precision. Each type can define its own formatting mini-language or interpretation of the format-spec field. The syntax of format specifications is as follows:

format-spec ::= std-format-spec | custom-format-spec std-format-spec ::= [[fill] align] [sign] ['#'] ['0'] [width] ['.' precision] [type] fill ::= <a character other than '{' or '}'> align ::= '<' | '>' | '=' | '^' sign ::= '+' | '-' | ' ' width ::= nonzero-digit [integer] | '{' arg-id '}' precision ::= integer | '{' arg-id '}' type ::= 'a' | 'A' | 'b' | 'B' | 'c' | 'd' | 'e' | 'E' | 'f' | 'F' | 'g' | 'G' | 'n' | 'o' | 'p' | 's' | 'x' | 'X'

where std-format-spec defines a common formatting mini-language supported by fundamental and string types, while custom-format-spec is a placeholder for user-defined mini-languages. Some of the formatting options are only supported for arithmetic types.

The fill character can be any character other than '{' or '}' . The presence of a fill character is signaled by the character following it, which must be one of the alignment options. If the second character of std-format-spec is not a valid alignment option, then it is assumed that both the fill character and the alignment option are absent.

The meaning of the various alignment options is as follows:

Option Meaning '<' Forces the field to be left-aligned within the available space. This is the default for non-arithmetic types, charT , and bool , unless an integer presentation type is specified. '>' Forces the field to be right-aligned within the available space. This is the default for arithmetic types other than charT and bool or when an integer presentation type is specified. '=' Forces the padding to be placed after the sign or prefix (if any) but before the digits. This is used for printing fields in the form +000000120 . This alignment option is only valid for arithmetic types other than charT and bool or when an integer presentation type is specified. '^' Forces the field to be centered within the available space by inserting N / 2 and N - N / 2 fill characters before and after the value respectively, where N is the total number of fill characters to insert.

[ Example:

char c = 120; string s0 = format("{:6}", 42); // s0 == " 42" string s1 = format("{:6}", 'x'); // s1 == "x " string s2 = format("{:*<6}", 'x'); // s2 == "x*****" string s3 = format("{:*>6}", 'x'); // s3 == "*****x" string s4 = format("{:*^6}", 'x'); // s4 == "**x***" string s5 = format("{:=6}", 'x'); // Error: '=' with charT and no integer presentation type string s6 = format("{:6d}", c); // s6 == " 120" string s7 = format("{:=+06d}", c); // s7 == "+00120" string s8 = format("{:0=#6x}", 0xa); // s8 == "0x000a" string s9 = format("{:6}", true); // s9 == "true "

Unless a minimum field width is defined, the field width will be determined by the size of the content and the alignment option will have no effect.

The sign option is only valid for arithmetic types other than charT and bool or when an integer presentation type is specified. It can be one of the following:

Option Meaning '+' Indicates that a sign should be used for both non-negative and negative numbers. '-' Indicates that a sign should be used only for negative numbers (this is the default behavior). space Indicates that a leading space should be used for non-negative numbers, and a minus sign for negative numbers.

The sign option applies to floating-point infinity and NaN.

double inf = numeric_limits<double>::infinity(); double nan = numeric_limits<double>::quiet_NaN(); string s0 = format("{0:} {0:+} {0:-} {0: }", 1); // s0 == "1 +1 1 1" string s1 = format("{0:} {0:+} {0:-} {0: }", -1); // s1 == "-1 -1 -1 -1" string s2 = format("{0:} {0:+} {0:-} {0: }", inf); // s2 == "inf +inf inf inf" string s3 = format("{0:} {0:+} {0:-} {0: }", nan); // s3 == "nan +nan nan nan"

The '#' option causes the alternate form to be used for the conversion. This option is only valid for arithmetic types other than charT and bool or when an integer presentation type is specified. For integers, when binary, octal, or hexadecimal output is used, this option adds the respective prefix "0b" ( "0B" ), "0" , or "0x" ( "0X" ) to the output value. Whether the prefix is lower-case or upper-case is determined by the case of the type format specifier. For floating-point numbers the alternate form causes the result of the conversion to always contain a decimal-point character, even if no digits follow it. Normally, a decimal-point character appears in the result of these conversions only if a digit follows it. In addition, for 'g' and 'G' conversions, trailing zeros are not removed from the result.

width is a decimal integer defining the minimum field width. If not specified, then the field width will be determined by the content.

Preceding the width field by a zero ( '0' ) character enables sign-aware zero-padding for arithmetic types. This is equivalent to a fill character of '0' with an alignment type of '=' .

The precision field is a decimal integer defining the precision or maximum field size. It can only be used with floating-point and string types. For floating-point types this field specifies the formatting precision. For string types it specifies how many characters will be used from the string.

Finally, the type determines how the data should be presented.

The available string presentation types are:

Type Meaning 's' Copies the string to the output. none The same as 's' .

The available charT presentation types are:

Type Meaning 'c' Copies the character to the output. none The same as 'c' .

Formatting of objects of arithmetic types and const void* is done as if by calling to_chars unless specified otherwise and copying the output through the output iterator of the format context with additional padding and adjustments as per format specifiers.

Let [first, last) be a range large enough to hold the to_chars output and value be the formatting argument value.

The available integer presentation types and their mapping to to_chars are:

Type Meaning 'b' to_chars(first, last, value, 2) ; using the '#' option with this type adds the prefix "0b" to the output. 'B' The same as 'b' , except that the '#' option adds the prefix "0B" to the output. 'd' to_chars(first, last, value) . 'o' to_chars(first, last, value, 8) ; using the '#' option with this type adds the prefix "0" to the output. 'x' to_chars(first, last, value, 16) ; using the '#' option with this type adds the prefix "0x" to the output. 'X' The same as 'x' , except that it uses uppercase letters for digits above 9 and the '#' option adds the prefix "0X" to the output. 'n' The same as 'd' , except that it uses the current global locale to insert the appropriate digit group separator characters. none The same as 'd' if the formatting argument type is not charT or bool .

Integer presentation types can also be used with charT and bool values. Values of type bool are formatted using textual representation, either "true" or "false" , if the presentation type is not specified.

string s0 = format("{}", 42); // s0 == "42" string s1 = format("{0:b} {0:d} {0:o} {0:x}", 42); // s1 == "101010 42 52 2a" string s2 = format("{0:#x} {0:#X}", 42); // s2 == "0x2a 0X2A" string s3 = format("{:n}", 1234); // s3 == "1,234" (depends on the locale)

The available floating-point presentation types and their mapping to to_chars (for values other than infinity and NaN) are:

Type Meaning 'a' If precision is specified, to_chars(first, last, value, chars_format::hex, precision) ; otherwise, to_chars(first, last, value, chars_format::hex) . 'A' The same as 'a' , except that it uses uppercase letters for digits above 9 and "P" to indicate the exponent. 'e' to_chars(first, last, value, chars_format::scientific, precision) ; precision defaults to 6 if not specified. 'E' The same as 'e' , except that it uses "E" to indicate exponent. 'f' to_chars(first, last, value, chars_format::fixed, precision) ; precision defaults to 6 if not specified. 'F' The same as 'f' . 'g' to_chars(first, last, value, chars_format::general, precision) ; precision defaults to 6 if not specified. 'G' The same as 'g' , except that it uses "E" to indicate exponent. 'n' The same as 'g' , except that it uses the current global locale to insert the appropriate digit group and decimal radix separator characters. none If precision is specified, to_chars(first, last, value, chars_format::general, precision) ; otherwise, to_chars(first, last, value) .

For lower-case presentation types, infinity and NaN are formatted as "inf" and "nan" , respectively, with sign, if any. For upper-case presentation types, infinity and NaN are formatted as "INF" and "NAN" , respectively, with sign, if any.

The available pointer presentation types and their mapping to to_chars are:

Type Meaning 'p' If uintptr_t is defined, to_chars(first, last, reinterpret_cast<uintptr_t>(value), 16) with the prefix "0x" added to the output; otherwise, implementation-defined. none The same as 'p' .

[ Note: Pointer presentation types also apply to nullptr_t . — end note ]

In the description of the functions, operator + is used for some of the iterator categories for which it does not have to be defined. In these cases the semantics of a + n are the same as in [algorithm.requirements].

template<class... Args> string format(string_view fmt, const Args&... args); Effects: Equivalent to: return vformat(fmt, make_format_args(args...)); template<class... Args> wstring format(wstring_view fmt, const Args&... args); Effects: Equivalent to: return vformat(fmt, make_wformat_args(args...)); string vformat(string_view fmt, format_args args); wstring vformat(wstring_view fmt, wformat_args args); Returns: A string object holding the character representation of formatting arguments provided by args formatted according to specifications given in fmt . Throws: format_error if fmt is not a format string. template<class Out, class... Args> Out format_to(Out out, string_view fmt, const Args&... args); template<class Out, class... Args> Out format_to(Out out, wstring_view fmt, const Args&... args); Effects: Equivalent to: using context = basic_format_context<Out, decltype(fmt)::value_type>; return vformat_to(out, fmt, {make_format_args<context>(args...)}); template<class Out> Out vformat_to(Out out, string_view fmt, format_args_t<Out, char> args); template<class Out> Out vformat_to(Out out, wstring_view fmt, format_args_t<Out, wchar_t> args); Let charT be decltype(fmt)::value_type . Constraints: Out satisfies OutputIterator<const charT&> . Expects: Out models OutputIterator<const charT&> . Effects: Places the character representation of formatting arguments provided by args , formatted according to specifications given in fmt , into the range [out, out + N) , where N = formatted_size(fmt, args...) . Returns: out + N . Throws: format_error if fmt is not a format string. template<class Out, class... Args> format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n, string_view fmt, const Args&... args); template<class Out, class... Args> format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n, wstring_view fmt, const Args&... args); Let charT be decltype(fmt)::value_type , N = formatted_size(fmt, args...) , and M = min(max(n, 0), N) . Constraints: Out satisfies OutputIterator<const charT&> . Expects: Out models OutputIterator<const charT&> , and formatter<T i , charT> meets the Formatter requirements for each T i in Args . Effects: Places the first M characters of the character representation of formatting arguments provided by args , formatted according to specifications given in fmt , into the range [out, out + M) . Returns: {out + M, N} . Throws: format_error if fmt is not a format string. template<class... Args> size_t formatted_size(string_view fmt, const Args&... args); template<class... Args> size_t formatted_size(wstring_view fmt, const Args&... args); Let charT be decltype(fmt)::value_type . Expects: formatter<T i , charT> meets the Formatter requirements for each T i in Args . Returns: The number of characters in the character representation of formatting arguments args formatted according to specifications given in fmt . Throws: format_error if fmt is not a format string.

The functions defined in [format.functions] use specializations of the class template formatter to format individual arguments.

Let charT be either char or wchar_t . Each specialization of formatter is either enabled or disabled, as described below. [ Note: Enabled specializations meet the Formatter requirements, and disabled specializations do not. — end note ] Each header that declares the template formatter provides enabled specializations:

template<> struct formatter< charT , charT >;

template<> struct formatter<char, wchar_t>;

template<> struct formatter< charT *, charT >;

template<> struct formatter<const charT *, charT >;

template<size_t N> struct formatter<const 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 >;

specializations of formatter for nullptr_t , void* , const void* , bool , and all cv-unqualified standard integer types, extended integer types, and floating-point types as the first template argument and charT as the second template argument,

formatter<wchar_t, char>

formatter<const char*, wchar_t>

Specializations such asandthat require implicit multibyte / wide string or character conversion are intentionally disabled.

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.

If the library provides an explicit or partial specialization of formatter<T, charT> , that specialization is enabled except as noted otherwise.

If F is a disabled specialization of formatter , these values are false : is_default_constructible_v<F> , is_copy_constructible_v<F> , is_move_constructible_v<F> , is_copy_assignable_v<F> , is_move_assignable_v<F> .

An enabled specialization formatter<T, charT> meets the Formatter requirements.

#include <format> 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) { 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"); // Ill-formed: disabled formatter std::string s2 = std::format("{}", red); // OK: user-provided formatter std::string s3 = std::format("{}", err{}); // Ill-formed: disabled formatter

A type F meets the Formatter requirements if:

it meets the Cpp17DefaultConstructible (Table 25), Cpp17CopyConstructible (Table 27), Cpp17CopyAssignable (Table 29), and Cpp17Destructible (Table 30) requirements,

(Table 25), (Table 27), (Table 29), and (Table 30) requirements, it is swappable ([swappable.requirements]) for lvalues, and

the expressions shown in Table � are valid and have the indicated semantics.

Given character type charT , output iterator type Out , and formatting argument type T , in Table � f is a value of type F , u is an lvalue of type T , t is a value of a type convertible to (possibly const) T , PC is basic_format_parse_context<charT> , FC is basic_format_context<Out, charT> , pc is an lvalue of type PC , and fc is an lvalue of type FC . pc.begin() points to the beginning of the format-spec ([format.syntax]) portion of the format string. If format-spec is empty then either pc.begin() == pc.end() or *pc.begin() == '}' .

Table � — Formatter requirements Expression Return type Requirement f.parse(pc) PC::iterator Parses format-spec ([format.string]) for type T in the range [pc.begin(), pc.end()) until the first unmatched character. Throws format_error unless the whole range is parsed or the unmatched character is '}' .

[ Note: This allows formatters to emit meaningful error messages. — end note ]

Stores the parsed format specifiers in *this and returns an iterator past the end of the parsed range. 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. The output shall only depend on t , the current global locale, and the range [pc.begin(), pc.end()) from the last call to f.parse(pc) . f.format(u, fc) FC::iterator As above but does not modify u .

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: explicit constexpr basic_format_parse_context(basic_string_view<charT> fmt, size_t num_args = 0) 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); }; }

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.

explicit constexpr basic_format_parse_context(basic_string_view<charT> fmt, size_t num_args = 0) noexcept; Effects: Initializes begin_ with fmt.begin() , end_ with fmt.end() , indexing_ with unknown , next_arg_id_ with 0 , and num_args_ with num_args . constexpr const_iterator begin() const noexcept; Returns: begin_ . constexpr const_iterator end() const noexcept; Returns: end_ . constexpr void advance_to(const_iterator it); Expects: end() is reachable from it . Effects: Equivalent to: begin_ = it; constexpr size_t next_arg_id(); Effects: If indexing_ != manual , equivalent to: if (indexing_ == unknown) indexing_ = automatic; return next_arg_id_++; Throws: format_error if indexing_ == manual which indicates mixing of automatic and manual argument indexing. constexpr void check_arg_id(size_t id); Effects: If indexing_ != automatic , equivalent to: if (indexing_ == unknown) indexing_ = manual; Throws: format_error if indexing_ == automatic which indicates mixing of automatic and manual argument indexing. Remarks: Call expressions where id >= num_args_ are not core constant expressions ([expr.const]).

namespace std { template<class Out, class charT> class basic_format_context { basic_format_args<basic_format_context> args_; // exposition only Out out_; // exposition only 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; iterator out(); void advance_to(iterator it); }; }

An instance of basic_format_context holds formatting state consisting of the formatting arguments and the output iterator.

Out shall model OutputIterator<const charT&> .

format_context is an alias for the instantiation of basic_format_context with an output iterator that appends to string such as back_insert_iterator<string> .

[ Note: For a given type charT , implementations are encouraged to provide a single instantiation of basic_format_context for appending to basic_string<charT> , vector<charT> , or any other container with contiguous storage by wrapping those in temporary objects with uniform interface (like span ) and polymorphic reallocation. — end note ]

basic_format_arg<basic_format_context> arg(size_t id) const; Returns: args_.get(id) . iterator out(); Returns: out_ . void advance_to(iterator it); Effects: Equivalent to: out_ = it;

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 get_char = [&]() { return iter != ctx.end() ? *iter : 0; }; if (get_char() != '{') return iter; ++iter; char c = get_char(); if (!isdigit(c) || (++iter, get_char()) != '}') throw format_error("invalid format"); width_arg_id = c - '0'; ctx.check_arg_id(width_arg_id); return ++iter; } // Formats S with width given by the argument width_arg_id. auto format(S s, format_context& ctx) { int width = visit_format_arg([](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"); else return value; }, ctx.arg(width_arg_id)); return format_to(ctx.out(), "{0:{1}}", s.value, width); } }; std::string s = std::format("{0:{1}}", S{42}, 10); // s == " 42"

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, double, long double, const char-type*, basic_string_view<char-type>, const void*, handle> value; // exposition only template<typename T> explicit basic_format_arg(const T& v) noexcept; // exposition only explicit basic_format_arg(float n) noexcept; // exposition only explicit basic_format_arg(double n) noexcept; // exposition only explicit basic_format_arg(long double n) noexcept; // exposition only explicit basic_format_arg(const char-type* s); // exposition only template<class traits> explicit basic_format_arg( basic_string_view<char-type, traits> s) noexcept; // exposition only template<class traits, class Allocator> explicit basic_format_arg( const basic_string<char-type, traits, Allocator>& s) noexcept; // exposition only explicit basic_format_arg(nullptr_t) noexcept; // exposition only template<class T> explicit basic_format_arg(const T* p) noexcept; // exposition only template<class Visitor, class Ctx> friend auto visit_format_arg(Visitor&& vis, basic_format_arg<Ctx> arg); // exposition only template<class Ctx, class... Args> friend format-arg-store<Ctx, Args...> make_format_args(const Args&... args); // exposition only public: basic_format_arg() noexcept; explicit operator bool() const noexcept; }; }

An instance of basic_format_arg provides access to a formatting argument for user-defined formatters.

The behavior of a program that adds specializations of basic_format_arg is undefined.

basic_format_arg() noexcept; Ensures: !(*this) . template<class T> explicit basic_format_arg(const T& v) noexcept; Constraints: typename Context::template formatter_type<T> is enabled. The extent to which an implementation determines that typename Context::template formatter_type<T> is enabled is unspecified, except that as a minimum the expression typename Context::template formatter_type<T>().format(declval<const T&>(), declval<Context&>()) shall be well-formed when treated as an unevaluated operand. Effects: if T is bool or char-type , initializes value with v ; otherwise,

is or , initializes with ; otherwise, if T is char and char-type is wchar_t , initializes value with static_cast<wchar_t>(v) ; otherwise,

is and is , initializes with ; otherwise, if T is a signed integer type ([basic.fundamental]) and sizeof(T) <= sizeof(int) , initializes value with static_cast<int>(v) ; otherwise,

is a signed integer type ([basic.fundamental]) and , initializes with ; otherwise, if T is an unsigned integer type and sizeof(T) <= sizeof(unsigned int) , initializes value with static_cast<unsigned int>(v) ; otherwise,

is an unsigned integer type and , initializes with ; otherwise, if T is a signed integer type and sizeof(T) <= sizeof(long long int) , initializes value with static_cast<long long int>(v) ; otherwise,

is a signed integer type and , initializes with ; otherwise, if T is an unsigned integer type and sizeof(T) <= sizeof(unsigned long long int) , initializes value with static_cast<unsigned long long int>(v) ; otherwise,

is an unsigned integer type and , initializes with ; otherwise, initializes value with handle(v) . explicit basic_format_arg(float n) noexcept; Effects: Initializes value with static_cast<double>(n) . explicit basic_format_arg(double n) noexcept;

explicit basic_format_arg(long double n) noexcept; Effects: Initializes value with n . explicit basic_format_arg(const char-type* s); Expects: s points to a NTCTS ([defns.ntcts]). Effects: Initializes value with s . template<class traits> explicit basic_format_arg(basic_string_view<char-type, traits> s) noexcept; Effects: Initializes value with s . template<class traits, class Allocator> explicit basic_format_arg( const basic_string<char-type, traits, Allocator>& s) noexcept; Effects: Initializes value with basic_string_view<char-type>(s.data(), s.size()) . explicit basic_format_arg(nullptr_t) noexcept; Effects: Initializes value with static_cast<const void*>(nullptr) . template<class T> explicit basic_format_arg(T* p) noexcept; Constraints: is_void_v<T> is true . Effects: Initializes value with p . [ Note: Constructing basic_format_arg from a pointer to a member is ill-formed unless the user provides an enabled specialization of formatter for this pointer to member type. — end note ] explicit operator bool() const noexcept; Returns: !holds_alternative<monostate>(value) .

The class handle allows formatting an object of a user-defined type.

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(const T& val) noexcept; // exposition only friend class basic_format_arg<Context>; // exposition only public: void format(basic_format_parse_context<char-type>&, Context& ctx) const; }; }

template<class T> explicit handle(const T& val) noexcept; Effects: Initializes ptr_ with addressof(val) and format_ with [](basic_format_parse_context<char-type>& parse_ctx, Context& format_ctx, const void* ptr) { typename Context::template formatter_type<T> f; parse_ctx.advance_to(f.parse(parse_ctx)); format_ctx.advance_to(f.format(*static_cast<const T*>(ptr), format_ctx)); } void format(basic_format_parse_context<char-type>& parse_ctx, Context& format_ctx) const; Effects: Equivalent to: format_(parse_ctx, format_ctx, ptr_);

20.�.5.2 Argument visitation [format.visit]

template<class Visitor, class Context> see below visit_format_arg(Visitor&& vis, basic_format_arg<Context> arg); Effects: Equivalent to: return visit(forward<Visitor>(vis), arg.value);

20.�.5.3 Class template format-arg-store [format.arg_store]

namespace std { template<class Context, class... Args> struct format-arg-store { // exposition only array<basic_format_arg<Context>, sizeof...(Args)> args; }; }

An instance of format-arg-store stores formatting arguments.

template<class Context = format_context, class... Args> format-arg-store<Context, Args...> make_format_args(const Args&... args); Expects: typename Context::template formatter_type<T i > meets the Formatter requirements for each T i in Args . Returns: {basic_format_arg<Context>(args)...} .

template<class... Args> format-arg-store<wformat_context, Args...> make_wformat_args(const Args&... args); Effects: Equivalent to: return make_format_args<wformat_context>(args...);

20.�.5.6 Class template basic_format_args [format.basic_args]

namespace std { template<class Context> class basic_format_args { size_t size_; // exposition only const basic_format_arg<Context>* data_; // exposition only public: basic_format_args() noexcept; template<class... Args> basic_format_args(const format-arg-store<Context, Args...>& store) noexcept; basic_format_arg<Context> get(size_t i) const noexcept; }; }

An instance of basic_format_args provides access to formatting arguments.

basic_format_args() noexcept; Effects: Initializes size_ with 0 .

template<class... Args> basic_format_args(const format-arg-store<Context, Args...>& store) noexcept; Effects: Initializes size_ with sizeof...(Args) and data_ with store.args.data() .

basic_format_arg<Context> get(size_t i) const noexcept; Returns: i < size_ ? data_[i] : basic_format_arg<Context>() .

basic_format_args

namespace std { class format_error : public runtime_error { public: explicit format_error(const string& what_arg); explicit format_error(const char* what_arg); }; }

Implementations are encouraged to optimize the representation offor small number of formatting arguments by storing indices of type alternatives separately from values and packing the former.

The class format_error defines the type of objects thrown as exceptions to report errors from the formatting library.