From Jason Turner

[format.formatter]

Diff to HTML by rtfpessoa

Files changed (1) hide show
  1. tmp/tmp1tu3mqev/{from.md → to.md} +125 -27
tmp/tmp1tu3mqev/{from.md → to.md} RENAMED
@@ -29,12 +29,12 @@ argument type `T`, in [[formatter.basic]] and [[formatter]]:
29
  - `pc` is an lvalue of type `PC`, and
30
  - `fc` is an lvalue of type `FC`.
31
 
32
  `pc.begin()` points to the beginning of the *format-spec*
33
  [[format.string]] of the replacement field being formatted in the format
34
- string. If *format-spec* is empty then either `pc.begin() == pc.end()`
35
- or `*pc.begin() == '}'`.
36
 
37
  [*Note 1*: This allows formatters to emit meaningful error
38
  messages. — *end note*]
39
 
40
  **Table: \newoldconcept{Formatter} requirements** <a id="formatter">[formatter]</a>
@@ -43,10 +43,22 @@ messages. — *end note*]
43
  | ----------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
44
  | `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`, `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)`. |
45
  | `f.format(u, fc)` | `FC::iterator` | As above, but does not modify `u`. |
46
 
47
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  #### Concept <a id="format.formattable">[[format.formattable]]</a>
49
 
50
  Let `fmt-iter-for<charT>` be an unspecified type that models
51
  `output_iterator<const charT&>` [[iterator.concept.output]].
52
 
@@ -62,11 +74,11 @@ template<class T, class Context,
62
  { cf.format(t, fc) } -> same_as<typename Context::iterator>;
63
  };
64
 
65
  template<class T, class charT>
66
  concept formattable =
67
- formattable-with<remove_reference_t<T>, basic_format_context<fmt-iter-for<charT>>>;
68
  ```
69
 
70
  A type `T` and a character type `charT` model `formattable` if
71
  `formatter<remove_cvref_t<T>, charT>` meets the requirements
72
  [[formatter.requirements]] and, if `remove_reference_t<T>` is
@@ -114,16 +126,37 @@ enabled specializations:
114
  template<> struct formatter<void*, charT>;
115
  template<> struct formatter<const void*, charT>;
116
  ```
117
 
118
  The `parse` member functions of these formatters interpret the format
119
- specification as a *std-format-spec* as described in
120
  [[format.string.std]].
121
 
122
- [*Note 1*: Specializations such as `formatter<wchar_t, char>` and
123
- `formatter<const char*, wchar_t>` that would require implicit multibyte
124
- / wide string or character conversion are disabled. — *end note*]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
 
126
  For any types `T` and `charT` for which neither the library nor the user
127
  provides an explicit or partial specialization of the class template
128
  `formatter`, `formatter<T, charT>` is disabled.
129
 
@@ -145,10 +178,11 @@ An enabled specialization `formatter<T, charT>` meets the requirements
145
 
146
  [*Example 1*:
147
 
148
  ``` cpp
149
  #include <format>
 
150
 
151
  enum color { red, green, blue };
152
  const char* color_names[] = { "red", "green", "blue" };
153
 
154
  template<> struct std::formatter<color> : std::formatter<const char*> {
@@ -238,18 +272,21 @@ the escaped string representation of a string of *C*, except that:
238
  [*Example 1*:
239
 
240
  ``` cpp
241
  string s0 = format("[{}]", "h\tllo"); // s0 has value: [h\ \ \ \ llo]
242
  string s1 = format("[{:?}]", "h\tllo"); // s1 has value: ["h\ tllo"]
 
243
  string s3 = format("[{:?}, {:?}]", '\'', '"'); // s3 has value: ['\ '', '"']
244
 
245
  // The following examples assume use of the UTF-8 encoding
246
  string s4 = format("[{:?}]", string("\0 \n \t \x02 \x1b", 9));
247
  // s4 has value: ["\ u{0\ \ n \ t \ u{2} \ u{1b}"]}
248
  string s5 = format("[{:?}]", "\xc3\x28"); // invalid UTF-8, s5 has value: ["\ x{c3\("]}
249
- string s7 = format("[{:?}]", "\u0301"); // s7 has value: ["\ u{301"]}
250
- string s8 = format("[{:?}]", "\\\u0301"); // s8 has value: ["\ \ \ u{301"]}
 
 
251
  ```
252
 
253
  — *end example*]
254
 
255
  #### Class template `basic_format_parse_context` <a id="format.parse.ctx">[[format.parse.ctx]]</a>
@@ -258,11 +295,11 @@ string s8 = format("[{:?}]", "\\\u0301"); // s8 has value: ["\ \ \ u{3
258
  namespace std {
259
  template<class charT>
260
  class basic_format_parse_context {
261
  public:
262
  using char_type = charT;
263
- using const_iterator = typename basic_string_view<charT>::const_iterator;
264
  using iterator = const_iterator;
265
 
266
  private:
267
  iterator begin_; // exposition only
268
  iterator end_; // exposition only
@@ -270,37 +307,49 @@ namespace std {
270
  indexing indexing_; // exposition only
271
  size_t next_arg_id_; // exposition only
272
  size_t num_args_; // exposition only
273
 
274
  public:
275
- constexpr explicit basic_format_parse_context(basic_string_view<charT> fmt,
276
- size_t num_args = 0) noexcept;
277
  basic_format_parse_context(const basic_format_parse_context&) = delete;
278
  basic_format_parse_context& operator=(const basic_format_parse_context&) = delete;
279
 
280
  constexpr const_iterator begin() const noexcept;
281
  constexpr const_iterator end() const noexcept;
282
  constexpr void advance_to(const_iterator it);
283
 
284
  constexpr size_t next_arg_id();
285
  constexpr void check_arg_id(size_t id);
 
 
 
 
 
286
  };
287
  }
288
  ```
289
 
290
  An instance of `basic_format_parse_context` holds the format string
291
- parsing state consisting of the format string range being parsed and the
292
- argument counter for automatic indexing.
 
 
 
 
293
 
294
  ``` cpp
295
- constexpr explicit basic_format_parse_context(basic_string_view<charT> fmt,
296
- size_t num_args = 0) noexcept;
297
  ```
298
 
299
  *Effects:* Initializes `begin_` with `fmt.begin()`, `end_` with
300
  `fmt.end()`, `indexing_` with `unknown`, `next_arg_id_` with `0`, and
301
- `num_args_` with `num_args`.
 
 
 
 
 
302
 
303
  ``` cpp
304
  constexpr const_iterator begin() const noexcept;
305
  ```
306
 
@@ -330,12 +379,14 @@ constexpr size_t next_arg_id();
330
  if (indexing_ == unknown)
331
  indexing_ = automatic;
332
  return next_arg_id_++;
333
  ```
334
 
335
- *Throws:* `format_error` if `indexing_ == manual` is `true` which
336
- indicates mixing of automatic and manual argument indexing.
 
 
337
 
338
  *Remarks:* Let *`cur-arg-id`* be the value of `next_arg_id_` prior to
339
  this call. Call expressions where *`cur-arg-id`*` >= num_args_` is
340
  `true` are not core constant expressions [[expr.const]].
341
 
@@ -348,25 +399,67 @@ constexpr void check_arg_id(size_t id);
348
  ``` cpp
349
  if (indexing_ == unknown)
350
  indexing_ = manual;
351
  ```
352
 
353
- *Throws:* `format_error` if `indexing_ == automatic` is `true` which
354
- indicates mixing of automatic and manual argument indexing.
355
 
356
- *Remarks:* Call expressions where `id >= num_args_` is `true` are not
357
- core constant expressions [[expr.const]].
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
358
 
359
  #### Class template `basic_format_context` <a id="format.context">[[format.context]]</a>
360
 
361
  ``` cpp
362
  namespace std {
363
  template<class Out, class charT>
364
  class basic_format_context {
365
  basic_format_args<basic_format_context> args_; // exposition only
366
  Out out_; // exposition only
367
 
 
 
 
368
  public:
369
  using iterator = Out;
370
  using char_type = charT;
371
  template<class T> using formatter_type = formatter<T, charT>;
372
 
@@ -380,10 +473,14 @@ namespace std {
380
  ```
381
 
382
  An instance of `basic_format_context` holds formatting state consisting
383
  of the formatting arguments and the output iterator.
384
 
 
 
 
 
385
  `Out` shall model `output_iterator<const charT&>`.
386
 
387
  `format_context` is an alias for a specialization of
388
  `basic_format_context` with an output iterator that appends to `string`,
389
  such as `back_insert_iterator<string>`. Similarly, `wformat_context` is
@@ -430,33 +527,34 @@ template<> struct std::formatter<S> {
430
  size_t width_arg_id = 0;
431
 
432
  // Parses a width argument id in the format { digit }.
433
  constexpr auto parse(format_parse_context& ctx) {
434
  auto iter = ctx.begin();
 
435
  auto get_char = [&]() { return iter != ctx.end() ? *iter : 0; };
436
  if (get_char() != '{')
437
  return iter;
438
  ++iter;
439
  char c = get_char();
440
- if (!isdigit(c) || (++iter, get_char()) != '}')
441
  throw format_error("invalid format");
442
  width_arg_id = c - '0';
443
  ctx.check_arg_id(width_arg_id);
444
  return ++iter;
445
  }
446
 
447
  // Formats an S with width given by the argument width_arg_id.
448
  auto format(S s, format_context& ctx) const {
449
- int width = visit_format_arg([](auto value) -> int {
450
  if constexpr (!is_integral_v<decltype(value)>)
451
  throw format_error("width is not integral");
452
  else if (value < 0 || value > numeric_limits<int>::max())
453
  throw format_error("invalid width");
454
  else
455
  return value;
456
- }, ctx.arg(width_arg_id));
457
- return format_to(ctx.out(), "{0:x<{1}}", s.value, width);
458
  }
459
  };
460
 
461
  std::string s = std::format("{0:{1}}", S{42}, 10); // value of s is "xxxxxxxx42"
462
  ```
 
29
  - `pc` is an lvalue of type `PC`, and
30
  - `fc` is an lvalue of type `FC`.
31
 
32
  `pc.begin()` points to the beginning of the *format-spec*
33
  [[format.string]] of the replacement field being formatted in the format
34
+ string. If *format-spec* is not present or empty then either
35
+ `pc.begin() == pc.end()` or `*pc.begin() == '}'`.
36
 
37
  [*Note 1*: This allows formatters to emit meaningful error
38
  messages. — *end note*]
39
 
40
  **Table: \newoldconcept{Formatter} requirements** <a id="formatter">[formatter]</a>
 
43
  | ----------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
44
  | `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`, `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)`. |
45
  | `f.format(u, fc)` | `FC::iterator` | As above, but does not modify `u`. |
46
 
47
 
48
+ #### Formatter locking <a id="format.formatter.locking">[[format.formatter.locking]]</a>
49
+
50
+ ``` cpp
51
+ template<class T>
52
+ constexpr bool enable_nonlocking_formatter_optimization = false;
53
+ ```
54
+
55
+ *Remarks:* Pursuant to [[namespace.std]], users may specialize
56
+ `enable_nonlocking_formatter_optimization` for cv-unqualified
57
+ program-defined types. Such specializations shall be usable in constant
58
+ expressions [[expr.const]] and have type `const bool`.
59
+
60
  #### Concept <a id="format.formattable">[[format.formattable]]</a>
61
 
62
  Let `fmt-iter-for<charT>` be an unspecified type that models
63
  `output_iterator<const charT&>` [[iterator.concept.output]].
64
 
 
74
  { cf.format(t, fc) } -> same_as<typename Context::iterator>;
75
  };
76
 
77
  template<class T, class charT>
78
  concept formattable =
79
+ formattable-with<remove_reference_t<T>, basic_format_context<fmt-iter-for<charT>, charT>>;
80
  ```
81
 
82
  A type `T` and a character type `charT` model `formattable` if
83
  `formatter<remove_cvref_t<T>, charT>` meets the requirements
84
  [[formatter.requirements]] and, if `remove_reference_t<T>` is
 
126
  template<> struct formatter<void*, charT>;
127
  template<> struct formatter<const void*, charT>;
128
  ```
129
 
130
  The `parse` member functions of these formatters interpret the format
131
+ specification as a *std-format-spec* as described in 
132
  [[format.string.std]].
133
 
134
+ Unless specified otherwise, for each type `T` for which a `formatter`
135
+ specialization is provided by the library, each of the headers provides
136
+ the following specialization:
137
+
138
+ ``` cpp
139
+ template<> inline constexpr bool enable_nonlocking_formatter_optimization<T> = true;
140
+ ```
141
+
142
+ [*Note 1*: Specializations such as `formatter<wchar_t, char>` that
143
+ would require implicit multibyte / wide string or character conversion
144
+ are disabled. — *end note*]
145
+
146
+ The header `<format>` provides the following disabled specializations:
147
+
148
+ - The string type specializations
149
+ ``` cpp
150
+ template<> struct formatter<char*, wchar_t>;
151
+ template<> struct formatter<const char*, wchar_t>;
152
+ template<size_t N> struct formatter<char[N], wchar_t>;
153
+ template<class traits, class Allocator>
154
+ struct formatter<basic_string<char, traits, Allocator>, wchar_t>;
155
+ template<class traits>
156
+ struct formatter<basic_string_view<char, traits>, wchar_t>;
157
+ ```
158
 
159
  For any types `T` and `charT` for which neither the library nor the user
160
  provides an explicit or partial specialization of the class template
161
  `formatter`, `formatter<T, charT>` is disabled.
162
 
 
178
 
179
  [*Example 1*:
180
 
181
  ``` cpp
182
  #include <format>
183
+ #include <string>
184
 
185
  enum color { red, green, blue };
186
  const char* color_names[] = { "red", "green", "blue" };
187
 
188
  template<> struct std::formatter<color> : std::formatter<const char*> {
 
272
  [*Example 1*:
273
 
274
  ``` cpp
275
  string s0 = format("[{}]", "h\tllo"); // s0 has value: [h\ \ \ \ llo]
276
  string s1 = format("[{:?}]", "h\tllo"); // s1 has value: ["h\ tllo"]
277
+ string s2 = format("[{:?}]", "\importexample[-2.5pt]{example_01}"); \kern1.25pt// s2 has value: ["\importexample[-2.5pt]{example_01"]}
278
  string s3 = format("[{:?}, {:?}]", '\'', '"'); // s3 has value: ['\ '', '"']
279
 
280
  // The following examples assume use of the UTF-8 encoding
281
  string s4 = format("[{:?}]", string("\0 \n \t \x02 \x1b", 9));
282
  // s4 has value: ["\ u{0\ \ n \ t \ u{2} \ u{1b}"]}
283
  string s5 = format("[{:?}]", "\xc3\x28"); // invalid UTF-8, s5 has value: ["\ x{c3\("]}
284
+ string s6 = format("[{:?}]", "\importexample{example_02}"); \kern0.75pt// s6 has value: ["\importexample{example_03{u}{200d}\importexample{example_04}"]}
285
+ string s7 = format("[{:?}]", "\u0301"); // s7 has value: ["\ u{301\"]}
286
+ string s8 = format("[{:?}]", "\\\u0301"); // s8 has value: ["\ \ \ u{301\"]}
287
+ string s9 = format("[{:?}]", "e\u0301\u0323"); // s9 has value: ["\importexample[-2pt]{example_06"]}
288
  ```
289
 
290
  — *end example*]
291
 
292
  #### Class template `basic_format_parse_context` <a id="format.parse.ctx">[[format.parse.ctx]]</a>
 
295
  namespace std {
296
  template<class charT>
297
  class basic_format_parse_context {
298
  public:
299
  using char_type = charT;
300
+ using const_iterator = basic_string_view<charT>::const_iterator;
301
  using iterator = const_iterator;
302
 
303
  private:
304
  iterator begin_; // exposition only
305
  iterator end_; // exposition only
 
307
  indexing indexing_; // exposition only
308
  size_t next_arg_id_; // exposition only
309
  size_t num_args_; // exposition only
310
 
311
  public:
312
+ constexpr explicit basic_format_parse_context(basic_string_view<charT> fmt) noexcept;
 
313
  basic_format_parse_context(const basic_format_parse_context&) = delete;
314
  basic_format_parse_context& operator=(const basic_format_parse_context&) = delete;
315
 
316
  constexpr const_iterator begin() const noexcept;
317
  constexpr const_iterator end() const noexcept;
318
  constexpr void advance_to(const_iterator it);
319
 
320
  constexpr size_t next_arg_id();
321
  constexpr void check_arg_id(size_t id);
322
+
323
+ template<class... Ts>
324
+ constexpr void check_dynamic_spec(size_t id) noexcept;
325
+ constexpr void check_dynamic_spec_integral(size_t id) noexcept;
326
+ constexpr void check_dynamic_spec_string(size_t id) noexcept;
327
  };
328
  }
329
  ```
330
 
331
  An instance of `basic_format_parse_context` holds the format string
332
+ parsing state, consisting of the format string range being parsed and
333
+ the argument counter for automatic indexing.
334
+
335
+ If a program declares an explicit or partial specialization of
336
+ `basic_format_parse_context`, the program is ill-formed, no diagnostic
337
+ required.
338
 
339
  ``` cpp
340
+ constexpr explicit basic_format_parse_context(basic_string_view<charT> fmt) noexcept;
 
341
  ```
342
 
343
  *Effects:* Initializes `begin_` with `fmt.begin()`, `end_` with
344
  `fmt.end()`, `indexing_` with `unknown`, `next_arg_id_` with `0`, and
345
+ `num_args_` with `0`.
346
+
347
+ [*Note 1*: Any call to `next_arg_id`, `check_arg_id`, or
348
+ `check_dynamic_spec` on an instance of `basic_format_parse_context`
349
+ initialized using this constructor is not a core constant
350
+ expression. — *end note*]
351
 
352
  ``` cpp
353
  constexpr const_iterator begin() const noexcept;
354
  ```
355
 
 
379
  if (indexing_ == unknown)
380
  indexing_ = automatic;
381
  return next_arg_id_++;
382
  ```
383
 
384
+ *Throws:* `format_error` if `indexing_ == manual` is `true`.
385
+
386
+ [*Note 2*: This indicates mixing of automatic and manual argument
387
+ indexing. — *end note*]
388
 
389
  *Remarks:* Let *`cur-arg-id`* be the value of `next_arg_id_` prior to
390
  this call. Call expressions where *`cur-arg-id`*` >= num_args_` is
391
  `true` are not core constant expressions [[expr.const]].
392
 
 
399
  ``` cpp
400
  if (indexing_ == unknown)
401
  indexing_ = manual;
402
  ```
403
 
404
+ *Throws:* `format_error` if `indexing_ == automatic` is `true`.
 
405
 
406
+ [*Note 3*: This indicates mixing of automatic and manual argument
407
+ indexing. *end note*]
408
+
409
+ *Remarks:* A call to this function is a core constant
410
+ expression [[expr.const]] only if `id < num_args_` is `true`.
411
+
412
+ ``` cpp
413
+ template<class... Ts>
414
+ constexpr void check_dynamic_spec(size_t id) noexcept;
415
+ ```
416
+
417
+ *Mandates:* `sizeof...(Ts)` ≥ 1. The types in `Ts...` are unique. Each
418
+ type in `Ts...` is one of `bool`, `char_type`, `int`, `unsigned int`,
419
+ `long long int`, `unsigned long long int`, `float`, `double`,
420
+ `long double`, `const char_type*`, `basic_string_view<char_type>`, or
421
+ `const void*`.
422
+
423
+ *Remarks:* A call to this function is a core constant expression only if
424
+
425
+ - `id < num_args_` is `true` and
426
+ - the type of the corresponding format argument (after conversion to
427
+ `basic_format_arg<Context>`) is one of the types in `Ts...`.
428
+
429
+ ``` cpp
430
+ constexpr void check_dynamic_spec_integral(size_t id) noexcept;
431
+ ```
432
+
433
+ *Effects:* Equivalent to:
434
+
435
+ ``` cpp
436
+ check_dynamic_spec<int, unsigned int, long long int, unsigned long long int>(id);
437
+ ```
438
+
439
+ ``` cpp
440
+ constexpr void check_dynamic_spec_string(size_t id) noexcept;
441
+ ```
442
+
443
+ *Effects:* Equivalent to:
444
+
445
+ ``` cpp
446
+ check_dynamic_spec<const char_type*, basic_string_view<char_type>>(id);
447
+ ```
448
 
449
  #### Class template `basic_format_context` <a id="format.context">[[format.context]]</a>
450
 
451
  ``` cpp
452
  namespace std {
453
  template<class Out, class charT>
454
  class basic_format_context {
455
  basic_format_args<basic_format_context> args_; // exposition only
456
  Out out_; // exposition only
457
 
458
+ basic_format_context(const basic_format_context&) = delete;
459
+ basic_format_context& operator=(const basic_format_context&) = delete;
460
+
461
  public:
462
  using iterator = Out;
463
  using char_type = charT;
464
  template<class T> using formatter_type = formatter<T, charT>;
465
 
 
473
  ```
474
 
475
  An instance of `basic_format_context` holds formatting state consisting
476
  of the formatting arguments and the output iterator.
477
 
478
+ If a program declares an explicit or partial specialization of
479
+ `basic_format_context`, the program is ill-formed, no diagnostic
480
+ required.
481
+
482
  `Out` shall model `output_iterator<const charT&>`.
483
 
484
  `format_context` is an alias for a specialization of
485
  `basic_format_context` with an output iterator that appends to `string`,
486
  such as `back_insert_iterator<string>`. Similarly, `wformat_context` is
 
527
  size_t width_arg_id = 0;
528
 
529
  // Parses a width argument id in the format { digit }.
530
  constexpr auto parse(format_parse_context& ctx) {
531
  auto iter = ctx.begin();
532
+ auto is_digit = [](auto c) { return c >= '0' && c <= '9'; };
533
  auto get_char = [&]() { return iter != ctx.end() ? *iter : 0; };
534
  if (get_char() != '{')
535
  return iter;
536
  ++iter;
537
  char c = get_char();
538
+ if (!is_digit(c) || (++iter, get_char()) != '}')
539
  throw format_error("invalid format");
540
  width_arg_id = c - '0';
541
  ctx.check_arg_id(width_arg_id);
542
  return ++iter;
543
  }
544
 
545
  // Formats an S with width given by the argument width_arg_id.
546
  auto format(S s, format_context& ctx) const {
547
+ int width = ctx.arg(width_arg_id).visit([](auto value) -> int {
548
  if constexpr (!is_integral_v<decltype(value)>)
549
  throw format_error("width is not integral");
550
  else if (value < 0 || value > numeric_limits<int>::max())
551
  throw format_error("invalid width");
552
  else
553
  return value;
554
+ });
555
+ return format_to(ctx.out(), "{0:x>{1}}", s.value, width);
556
  }
557
  };
558
 
559
  std::string s = std::format("{0:{1}}", S{42}, 10); // value of s is "xxxxxxxx42"
560
  ```