The following is in preparation for the SG16 telecon scheduled
for tomorrow.
LWG3639 tracks how implementations should handle fill characters that have an estimated width other than 1 (the current proposed resolution for LWG3576 limits fill characters to those encodeable as a single code point in the ordinary literal encoding). The issue discussion records three possible ways to resolve the issue:
Assuming that we elect to allow characters with an estimated width other than 1 to be used as fill characters (e.g., we reject option 3 above), I think the normative guidance offered in [format.string.std]p11 suffices to direct implementations to choose between options 1 and 2; option 1 should be used for Unicode encodings, and option 2 otherwise. This effectively limits the options under consideration to just two.
If characters that have estimated widths other than 1 are not
permitted as fill characters, then whether a program is correct or
not may depend on what encoding is used for the ordinary literal
encoding. For example, Shift-JIS supports encoding katakana as
either half-width or full-width (e.g., ï½¶ U+FF76 {HALFWIDTH
KATAKANA LETTER KA} or ã‚« U+30AB {KATAKANA LETTER KA}). Since
Shift-JIS is not a Unicode encoding, an implementation may assign
all such characters an estimated width of 1, but the full-width
variants would have an estimated width of 2 for a Unicode
encoding. I have no perspective on whether such full-width
characters would ever be desirable as fill characters and thus
prefer not to prohibit them without strong cause.
If the estimated width of the fill character is greater than 1,
then alignment to the end of the field might not be possible. For
example:
 std::format("{:🤡>4}", 123);
There are a number of options available to handle such cases:
There are also two related wording omissions:
In some cases, it would be possible for field alignment to be
restored by tracking underfill and overfill counts and
underfilling or overfilling later fields. That ... is probably not
a good idea.
The wording below is intended to address LWG3639 and
to supersede the current proposed resolution for LWG3576.
Change [format.string.std]p1:
[...]
 The syntax of format specifications is as follows:
[...]
fill:
any
charactermember of the translation character set ([lex.charset]) other than{U+007B LEFT CURLY BRACKET or}U+007D RIGHT CURLY BRACKET
[...]
Change [format.string.std]p2:
The fill character is the character denoted by the fill specifier or, if the fill specifier is absent, U+0020 SPACE.
[Note 2:
The fill character can be any character other than { or }.The presence of afill characterfill specifier 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 thatboth the fill character and the alignment option arethe fill-and-align specifier is absent. — end note]
Change [format.string.std]p3:
The align specifier applies to all argument types. The meaning of the various alignment options is as specified in Table 62.
[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>}", "12345678"); // value of s7 is "12345678"
— end example]
[Note 3: Unless a minimum field width is defined, the field width is determined by the size of the content and the alignment option has no effect. — end note]
[Note 4: If the width of the formatting argument value exceeds the field width, then the alignment option has no effect. — end note]
[Note 5: It may not be possible to exactly align the formatting argument value within the available space when the fill character has an estimated width other than 1. — end note]
Table 62: Meaning of align options [tab:format.align]
Option
Meaning
<
Forces the field to be aligned to the start of the available space by inserting n fill characters after the formatting argument value where n is the number of fill characters needed to most closely align to the field width without exceeding it. This is the default for non-arithmetic types, charT, and bool, unless an integer presentation type is specified.
>
Forces the field to be aligned to the end of the available space by inserting n fill characters before the formatting argument value where n is the number of fill characters needed to most closely align to the field width without exceeding it. This is the default 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⌋ fill characters before and ⌈n/2⌉ fill characters after the formatting argument value, where n is the total number of fill characters to insertneeded to most closely align to the field width without exceeding it.
Tom.