From Jason Turner

[tuple]

Diff to HTML by rtfpessoa

Files changed (1) hide show
  1. tmp/tmpf7a48v0o/{from.md → to.md} +484 -147
tmp/tmpf7a48v0o/{from.md → to.md} RENAMED
@@ -11,17 +11,32 @@ arguments is similar to an instantiation of `pair` with the same two
11
  arguments. See  [[pairs]].
12
 
13
  ### Header `<tuple>` synopsis <a id="tuple.syn">[[tuple.syn]]</a>
14
 
15
  ``` cpp
 
16
  #include <compare> // see [compare.syn]
17
 
18
  namespace std {
19
  // [tuple.tuple], class template tuple
20
  template<class... Types>
21
  class tuple;
22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  // [tuple.creation], tuple creation functions
24
  inline constexpr unspecified ignore;
25
 
26
  template<class... TTypes>
27
  constexpr tuple<unwrap_ref_decay_t<TTypes>...> make_tuple(TTypes&&...);
@@ -30,18 +45,18 @@ namespace std {
30
  constexpr tuple<TTypes&&...> forward_as_tuple(TTypes&&...) noexcept;
31
 
32
  template<class... TTypes>
33
  constexpr tuple<TTypes&...> tie(TTypes&...) noexcept;
34
 
35
- template<class... Tuples>
36
  constexpr tuple<CTypes...> tuple_cat(Tuples&&...);
37
 
38
  // [tuple.apply], calling a function with a tuple of arguments
39
- template<class F, class Tuple>
40
- constexpr decltype(auto) apply(F&& f, Tuple&& t);
41
 
42
- template<class T, class Tuple>
43
  constexpr T make_from_tuple(Tuple&& t);
44
 
45
  // [tuple.helper], tuple helper classes
46
  template<class T> struct tuple_size; // not defined
47
  template<class T> struct tuple_size<const T>;
@@ -76,28 +91,45 @@ namespace std {
76
  constexpr const T&& get(const tuple<Types...>&& t) noexcept;
77
 
78
  // [tuple.rel], relational operators
79
  template<class... TTypes, class... UTypes>
80
  constexpr bool operator==(const tuple<TTypes...>&, const tuple<UTypes...>&);
 
 
81
  template<class... TTypes, class... UTypes>
82
  constexpr common_comparison_category_t<synth-three-way-result<TTypes, UTypes>...>
83
  operator<=>(const tuple<TTypes...>&, const tuple<UTypes...>&);
 
 
84
 
85
  // [tuple.traits], allocator-related traits
86
  template<class... Types, class Alloc>
87
  struct uses_allocator<tuple<Types...>, Alloc>;
88
 
89
  // [tuple.special], specialized algorithms
90
  template<class... Types>
91
  constexpr void swap(tuple<Types...>& x, tuple<Types...>& y) noexcept(see below);
 
 
92
 
93
  // [tuple.helper], tuple helper classes
94
  template<class T>
95
- inline constexpr size_t tuple_size_v = tuple_size<T>::value;
96
  }
97
  ```
98
 
 
 
 
 
 
 
 
 
 
 
 
99
  ### Class template `tuple` <a id="tuple.tuple">[[tuple.tuple]]</a>
100
 
101
  ``` cpp
102
  namespace std {
103
  template<class... Types>
@@ -110,19 +142,30 @@ namespace std {
110
  constexpr explicit(see below) tuple(UTypes&&...); // only if sizeof...(Types) >= 1
111
 
112
  tuple(const tuple&) = default;
113
  tuple(tuple&&) = default;
114
 
 
 
115
  template<class... UTypes>
116
  constexpr explicit(see below) tuple(const tuple<UTypes...>&);
117
  template<class... UTypes>
118
  constexpr explicit(see below) tuple(tuple<UTypes...>&&);
 
 
119
 
 
 
120
  template<class U1, class U2>
121
  constexpr explicit(see below) tuple(const pair<U1, U2>&); // only if sizeof...(Types) == 2
122
  template<class U1, class U2>
123
  constexpr explicit(see below) tuple(pair<U1, U2>&&); // only if sizeof...(Types) == 2
 
 
 
 
 
124
 
125
  // allocator-extended constructors
126
  template<class Alloc>
127
  constexpr explicit(see below)
128
  tuple(allocator_arg_t, const Alloc& a);
@@ -134,39 +177,71 @@ namespace std {
134
  tuple(allocator_arg_t, const Alloc& a, UTypes&&...);
135
  template<class Alloc>
136
  constexpr tuple(allocator_arg_t, const Alloc& a, const tuple&);
137
  template<class Alloc>
138
  constexpr tuple(allocator_arg_t, const Alloc& a, tuple&&);
 
 
 
139
  template<class Alloc, class... UTypes>
140
  constexpr explicit(see below)
141
  tuple(allocator_arg_t, const Alloc& a, const tuple<UTypes...>&);
142
  template<class Alloc, class... UTypes>
143
  constexpr explicit(see below)
144
  tuple(allocator_arg_t, const Alloc& a, tuple<UTypes...>&&);
 
 
 
 
 
 
145
  template<class Alloc, class U1, class U2>
146
  constexpr explicit(see below)
147
  tuple(allocator_arg_t, const Alloc& a, const pair<U1, U2>&);
148
  template<class Alloc, class U1, class U2>
149
  constexpr explicit(see below)
150
  tuple(allocator_arg_t, const Alloc& a, pair<U1, U2>&&);
 
 
 
 
 
 
151
 
152
  // [tuple.assign], tuple assignment
153
  constexpr tuple& operator=(const tuple&);
 
154
  constexpr tuple& operator=(tuple&&) noexcept(see below);
 
155
 
156
  template<class... UTypes>
157
  constexpr tuple& operator=(const tuple<UTypes...>&);
 
 
158
  template<class... UTypes>
159
  constexpr tuple& operator=(tuple<UTypes...>&&);
 
 
160
 
161
  template<class U1, class U2>
162
  constexpr tuple& operator=(const pair<U1, U2>&); // only if sizeof...(Types) == 2
 
 
 
163
  template<class U1, class U2>
164
  constexpr tuple& operator=(pair<U1, U2>&&); // only if sizeof...(Types) == 2
 
 
 
 
 
 
 
165
 
166
  // [tuple.swap], tuple swap
167
  constexpr void swap(tuple&) noexcept(see below);
 
168
  };
169
 
170
  template<class... UTypes>
171
  tuple(UTypes...) -> tuple<UTypes...>;
172
  template<class T1, class T2>
@@ -190,17 +265,19 @@ indexing is zero-based.
190
  For each `tuple` constructor, an exception is thrown only if the
191
  construction of one of the types in `Types` throws an exception.
192
 
193
  The defaulted move and copy constructor, respectively, of `tuple` is a
194
  constexpr function if and only if all required element-wise
195
- initializations for move and copy, respectively, would satisfy the
196
- requirements for a constexpr function. The defaulted move and copy
197
  constructor of `tuple<>` are constexpr functions.
198
 
199
  If `is_trivially_destructible_v<Tᵢ>` is `true` for all `Tᵢ`, then the
200
  destructor of `tuple` is trivial.
201
 
 
 
202
  ``` cpp
203
  constexpr explicit(see below) tuple();
204
  ```
205
 
206
  *Constraints:* `is_default_constructible_v<``Tᵢ``>` is `true` for all i.
@@ -232,23 +309,43 @@ parameter.
232
 
233
  ``` cpp
234
  template<class... UTypes> constexpr explicit(see below) tuple(UTypes&&... u);
235
  ```
236
 
237
- *Constraints:* `sizeof...(Types)` equals `sizeof...(UTypes)` and
238
- `sizeof...(Types)` ≥ 1 and `is_constructible_v<``Tᵢ``, ``Uᵢ``>` is
239
- `true` for all i.
 
 
 
 
 
 
 
 
 
 
 
 
240
 
241
  *Effects:* Initializes the elements in the tuple with the corresponding
242
  value in `std::forward<UTypes>(u)`.
243
 
244
  *Remarks:* The expression inside `explicit` is equivalent to:
245
 
246
  ``` cpp
247
  !conjunction_v<is_convertible<UTypes, Types>...>
248
  ```
249
 
 
 
 
 
 
 
 
 
250
  ``` cpp
251
  tuple(const tuple& u) = default;
252
  ```
253
 
254
  *Mandates:* `is_copy_constructible_v<``Tᵢ``>` is `true` for all i.
@@ -264,91 +361,108 @@ tuple(tuple&& u) = default;
264
 
265
  *Effects:* For all i, initializes the iᵗʰ element of `*this` with
266
  `std::forward<``Tᵢ``>(get<`i`>(u))`.
267
 
268
  ``` cpp
 
269
  template<class... UTypes> constexpr explicit(see below) tuple(const tuple<UTypes...>& u);
270
- ```
271
-
272
- *Constraints:*
273
-
274
- - `sizeof...(Types)` equals `sizeof...(UTypes)` and
275
- - `is_constructible_v<``Tᵢ``, const ``Uᵢ``&>` is `true` for all i, and
276
- - either `sizeof...(Types)` is not 1, or (when `Types...` expands to `T`
277
- and `UTypes...` expands to `U`)
278
- `is_convertible_v<const tuple<U>&, T>`,
279
- `is_constructible_v<T, const tuple<U>&>`, and `is_same_v<T, U>` are
280
- all `false`.
281
-
282
- *Effects:* Initializes each element of `*this` with the corresponding
283
- element of `u`.
284
-
285
- *Remarks:* The expression inside `explicit` is equivalent to:
286
-
287
- ``` cpp
288
- !conjunction_v<is_convertible<const UTypes&, Types>...>
289
- ```
290
-
291
- ``` cpp
292
  template<class... UTypes> constexpr explicit(see below) tuple(tuple<UTypes...>&& u);
 
293
  ```
294
 
 
 
 
295
  *Constraints:*
296
 
297
  - `sizeof...(Types)` equals `sizeof...(UTypes)`, and
298
- - `is_constructible_v<``Tᵢ``, ``Uᵢ``>` is `true` for all i, and
 
299
  - either `sizeof...(Types)` is not 1, or (when `Types...` expands to `T`
300
- and `UTypes...` expands to `U`) `is_convertible_v<tuple<U>, T>`,
301
- `is_constructible_v<T, tuple<U>>`, and `is_same_v<T, U>` are all
302
  `false`.
303
 
304
- *Effects:* For all i, initializes the iᵗʰ element of `*this` with
305
- `std::forward<``Uᵢ``>(get<`i`>(u))`.
306
 
307
  *Remarks:* The expression inside `explicit` is equivalent to:
308
 
309
  ``` cpp
310
- !conjunction_v<is_convertible<UTypes, Types>...>
311
  ```
312
 
 
 
 
 
 
 
 
 
313
  ``` cpp
 
314
  template<class U1, class U2> constexpr explicit(see below) tuple(const pair<U1, U2>& u);
315
- ```
316
-
317
- *Constraints:*
318
-
319
- - `sizeof...(Types)` is 2,
320
- - `is_constructible_v<``T₀``, const U1&>` is `true`, and
321
- - `is_constructible_v<``T₁``, const U2&>` is `true`.
322
-
323
- *Effects:* Initializes the first element with `u.first` and the second
324
- element with `u.second`.
325
-
326
- The expression inside `explicit` is equivalent to:
327
-
328
- ``` cpp
329
- !is_convertible_v<const U1&, $T_0$> || !is_convertible_v<const U2&, $T_1$>
330
- ```
331
-
332
- ``` cpp
333
  template<class U1, class U2> constexpr explicit(see below) tuple(pair<U1, U2>&& u);
 
334
  ```
335
 
 
 
336
  *Constraints:*
337
 
338
  - `sizeof...(Types)` is 2,
339
- - `is_constructible_v<``T₀``, U1>` is `true`, and
340
- - `is_constructible_v<``T₁``, U2>` is `true`.
 
 
341
 
342
- *Effects:* Initializes the first element with
343
- `std::forward<U1>(u.first)` and the second element with
344
- `std::forward<U2>(u.second)`.
345
 
346
- The expression inside `explicit` is equivalent to:
347
 
348
  ``` cpp
349
- !is_convertible_v<U1, $T_0$> || !is_convertible_v<U2, $T_1$>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
350
  ```
351
 
352
  ``` cpp
353
  template<class Alloc>
354
  constexpr explicit(see below)
@@ -361,26 +475,41 @@ template<class Alloc, class... UTypes>
361
  tuple(allocator_arg_t, const Alloc& a, UTypes&&...);
362
  template<class Alloc>
363
  constexpr tuple(allocator_arg_t, const Alloc& a, const tuple&);
364
  template<class Alloc>
365
  constexpr tuple(allocator_arg_t, const Alloc& a, tuple&&);
 
 
 
366
  template<class Alloc, class... UTypes>
367
  constexpr explicit(see below)
368
  tuple(allocator_arg_t, const Alloc& a, const tuple<UTypes...>&);
369
  template<class Alloc, class... UTypes>
370
  constexpr explicit(see below)
371
  tuple(allocator_arg_t, const Alloc& a, tuple<UTypes...>&&);
 
 
 
 
 
 
372
  template<class Alloc, class U1, class U2>
373
  constexpr explicit(see below)
374
  tuple(allocator_arg_t, const Alloc& a, const pair<U1, U2>&);
375
  template<class Alloc, class U1, class U2>
376
  constexpr explicit(see below)
377
  tuple(allocator_arg_t, const Alloc& a, pair<U1, U2>&&);
 
 
 
 
 
 
378
  ```
379
 
380
- *Preconditions:* `Alloc` meets the *Cpp17Allocator* requirements
381
- ([[cpp17.allocator]]).
382
 
383
  *Effects:* Equivalent to the preceding constructors except that each
384
  element is constructed with uses-allocator
385
  construction [[allocator.uses.construction]].
386
 
@@ -398,13 +527,24 @@ constexpr tuple& operator=(const tuple& u);
398
  ```
399
 
400
  *Effects:* Assigns each element of `u` to the corresponding element of
401
  `*this`.
402
 
 
 
403
  *Remarks:* This operator is defined as deleted unless
404
  `is_copy_assignable_v<``Tᵢ``>` is `true` for all i.
405
 
 
 
 
 
 
 
 
 
 
406
  *Returns:* `*this`.
407
 
408
  ``` cpp
409
  constexpr tuple& operator=(tuple&& u) noexcept(see below);
410
  ```
@@ -412,19 +552,31 @@ constexpr tuple& operator=(tuple&& u) noexcept(see below);
412
  *Constraints:* `is_move_assignable_v<``Tᵢ``>` is `true` for all i.
413
 
414
  *Effects:* For all i, assigns `std::forward<``Tᵢ``>(get<`i`>(u))` to
415
  `get<`i`>(*this)`.
416
 
417
- *Remarks:* The expression inside `noexcept` is equivalent to the logical
418
- <span class="smallcaps">and</span> of the following expressions:
 
 
419
 
420
  ``` cpp
421
  is_nothrow_move_assignable_v<Tᵢ>
422
  ```
423
 
424
  where Tᵢ is the iᵗʰ type in `Types`.
425
 
 
 
 
 
 
 
 
 
 
 
426
  *Returns:* `*this`.
427
 
428
  ``` cpp
429
  template<class... UTypes> constexpr tuple& operator=(const tuple<UTypes...>& u);
430
  ```
@@ -437,10 +589,24 @@ template<class... UTypes> constexpr tuple& operator=(const tuple<UTypes...>& u);
437
  *Effects:* Assigns each element of `u` to the corresponding element of
438
  `*this`.
439
 
440
  *Returns:* `*this`.
441
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
442
  ``` cpp
443
  template<class... UTypes> constexpr tuple& operator=(tuple<UTypes...>&& u);
444
  ```
445
 
446
  *Constraints:*
@@ -451,10 +617,24 @@ template<class... UTypes> constexpr tuple& operator=(tuple<UTypes...>&& u);
451
  *Effects:* For all i, assigns `std::forward<``Uᵢ``>(get<`i`>(u))` to
452
  `get<`i`>(*this)`.
453
 
454
  *Returns:* `*this`.
455
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
456
  ``` cpp
457
  template<class U1, class U2> constexpr tuple& operator=(const pair<U1, U2>& u);
458
  ```
459
 
460
  *Constraints:*
@@ -466,10 +646,25 @@ template<class U1, class U2> constexpr tuple& operator=(const pair<U1, U2>& u);
466
  *Effects:* Assigns `u.first` to the first element of `*this` and
467
  `u.second` to the second element of `*this`.
468
 
469
  *Returns:* `*this`.
470
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
471
  ``` cpp
472
  template<class U1, class U2> constexpr tuple& operator=(pair<U1, U2>&& u);
473
  ```
474
 
475
  *Constraints:*
@@ -482,40 +677,96 @@ template<class U1, class U2> constexpr tuple& operator=(pair<U1, U2>&& u);
482
  `*this` and
483
  `std::forward<U2>(u.second)` to the second element of `*this`.
484
 
485
  *Returns:* `*this`.
486
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
487
  #### `swap` <a id="tuple.swap">[[tuple.swap]]</a>
488
 
489
  ``` cpp
490
  constexpr void swap(tuple& rhs) noexcept(see below);
 
491
  ```
492
 
493
- *Preconditions:* Each element in `*this` is swappable
494
- with [[swappable.requirements]] the corresponding element in `rhs`.
495
 
496
- *Effects:* Calls `swap` for each element in `*this` and its
497
- corresponding element in `rhs`.
498
 
499
- *Remarks:* The expression inside `noexcept` is equivalent to the logical
500
- <span class="smallcaps">and</span> of the following expressions:
 
501
 
502
- ``` cpp
503
- is_nothrow_swappable_v<Tᵢ>
504
- ```
505
 
506
- where Tᵢ is the iᵗʰ type in `Types`.
 
507
 
508
  *Throws:* Nothing unless one of the element-wise `swap` calls throws an
509
  exception.
510
 
 
 
 
 
 
 
511
  ### Tuple creation functions <a id="tuple.creation">[[tuple.creation]]</a>
512
 
513
- In the function descriptions that follow, the members of a template
514
- parameter pack `XTypes` are denoted by `X`ᵢ for i in \[`0`,
515
- `sizeof...(`*X*`Types)`) in order, where indexing is zero-based.
516
-
517
  ``` cpp
518
  template<class... TTypes>
519
  constexpr tuple<unwrap_ref_decay_t<TTypes>...> make_tuple(TTypes&&... t);
520
  ```
521
 
@@ -524,11 +775,11 @@ template<class... TTypes>
524
 
525
  [*Example 1*:
526
 
527
  ``` cpp
528
  int i; float j;
529
- make_tuple(1, ref(i), cref(j))
530
  ```
531
 
532
  creates a tuple of type `tuple<int, int&, const float&>`.
533
 
534
  — *end example*]
@@ -568,90 +819,96 @@ tie(i, ignore, s) = make_tuple(42, 3.14, "C++");
568
  ```
569
 
570
  — *end example*]
571
 
572
  ``` cpp
573
- template<class... Tuples>
574
  constexpr tuple<CTypes...> tuple_cat(Tuples&&... tpls);
575
  ```
576
 
577
- In the following paragraphs, let `Tᵢ` be the iᵗʰ type in `Tuples`, `Uᵢ`
578
- be `remove_reference_t<T`ᵢ`>`, and `tpᵢ` be the iᵗʰ parameter in the
579
- function parameter pack `tpls`, where all indexing is zero-based.
580
 
581
- *Preconditions:* For all i, `Uᵢ` is the type cvᵢ `tuple<``Argsᵢ``...>`,
582
- where cvᵢ is the (possibly empty) iᵗʰ *cv-qualifier-seq* and `Argsᵢ` is
583
- the template parameter pack representing the element types in `Uᵢ`. Let
584
- `A_ik` be the kᵗʰ type in `Argsᵢ`. For all `A_ik` the following
585
- requirements are met:
 
 
 
 
586
 
587
- - If `Tᵢ` is deduced as an lvalue reference type, then
588
- `is_constructible_v<``A_ik``, `cvᵢ `A_ik``&> == true`, otherwise
589
- - `is_constructible_v<``A_ik``, `cvᵢ `A_ik``&&> == true`.
 
590
 
591
- *Remarks:* The types in `CTypes` are equal to the ordered sequence of
592
- the extended types `Args₀``..., ``Args₁``..., `…`, ``Args_n-1``...`,
593
- where n is equal to `sizeof...(Tuples)`. Let `eᵢ``...` be the iᵗʰ
594
- ordered sequence of tuple elements of the resulting `tuple` object
595
- corresponding to the type sequence `Argsᵢ`.
596
 
597
- *Returns:* A `tuple` object constructed by initializing the kᵢᵗʰ type
598
- element `e_ik` in `eᵢ``...` with
599
-
600
- ``` cpp
601
- get<kᵢ>(std::forward<$T_i$>($tp_i$))
602
- ```
603
-
604
- for each valid kᵢ and each group `eᵢ` in order.
605
-
606
- [*Note 1*: An implementation may support additional types in the
607
- template parameter pack `Tuples` that support the `tuple`-like protocol,
608
- such as `pair` and `array`. — *end note*]
609
 
610
  ### Calling a function with a `tuple` of arguments <a id="tuple.apply">[[tuple.apply]]</a>
611
 
612
  ``` cpp
613
- template<class F, class Tuple>
614
- constexpr decltype(auto) apply(F&& f, Tuple&& t);
615
  ```
616
 
617
  *Effects:* Given the exposition-only function:
618
 
619
  ``` cpp
620
- template<class F, class Tuple, size_t... I>
 
621
  constexpr decltype(auto) apply-impl(F&& f, Tuple&& t, index_sequence<I...>) {
622
  // exposition only
623
- return INVOKE(std::forward<F>(f), std::get<I>(std::forward<Tuple>(t))...); // see [func.require]
 
624
  }
625
  ```
626
 
627
  Equivalent to:
628
 
629
  ``` cpp
630
  return apply-impl(std::forward<F>(f), std::forward<Tuple>(t),
631
  make_index_sequence<tuple_size_v<remove_reference_t<Tuple>>>{});
632
  ```
633
 
 
 
 
 
634
  ``` cpp
635
- template<class T, class Tuple>
 
 
 
 
636
  constexpr T make_from_tuple(Tuple&& t);
637
  ```
638
 
 
 
 
 
639
  *Effects:* Given the exposition-only function:
640
 
641
  ``` cpp
642
- template<class T, class Tuple, size_t... I>
 
 
643
  constexpr T make-from-tuple-impl(Tuple&& t, index_sequence<I...>) { // exposition only
644
  return T(get<I>(std::forward<Tuple>(t))...);
645
  }
 
646
  ```
647
 
648
  Equivalent to:
649
 
650
  ``` cpp
651
  return make-from-tuple-impl<T>(
652
- forward<Tuple>(t),
653
  make_index_sequence<tuple_size_v<remove_reference_t<Tuple>>>{});
654
  ```
655
 
656
  [*Note 1*: The type of `T` must be supplied as an explicit template
657
  parameter, as it cannot be deduced from the argument
@@ -688,13 +945,13 @@ is zero-based.
688
  template<class T> struct tuple_size<const T>;
689
  ```
690
 
691
  Let `TS` denote `tuple_size<T>` of the cv-unqualified type `T`. If the
692
  expression `TS::value` is well-formed when treated as an unevaluated
693
- operand, then each specialization of the template meets the
694
- *Cpp17UnaryTypeTrait* requirements [[meta.rqmts]] with a base
695
- characteristic of
696
 
697
  ``` cpp
698
  integral_constant<size_t, TS::value>
699
  ```
700
 
@@ -754,11 +1011,11 @@ is a non-reference type `T`, the return type is `T&&`. — *end note*]
754
 
755
  [*Note 2*: \[Note B\]Constness is shallow. If a type `T` in `Types` is
756
  some reference type `X&`, the return type is `X&`, not `const X&`.
757
  However, if the element type is a non-reference type `T`, the return
758
  type is `const T&`. This is consistent with how constness is defined to
759
- work for member variables of reference type. — *end note*]
760
 
761
  ``` cpp
762
  template<class T, class... Types>
763
  constexpr T& get(tuple<Types...>& t) noexcept;
764
  template<class T, class... Types>
@@ -793,75 +1050,155 @@ type depended on a template parameter would have required using the
793
  ### Relational operators <a id="tuple.rel">[[tuple.rel]]</a>
794
 
795
  ``` cpp
796
  template<class... TTypes, class... UTypes>
797
  constexpr bool operator==(const tuple<TTypes...>& t, const tuple<UTypes...>& u);
 
 
798
  ```
799
 
 
 
800
  *Mandates:* For all `i`, where 0 ≤ `i` < `sizeof...(TTypes)`,
801
- `get<i>(t) == get<i>(u)` is a valid expression returning a type that is
802
- convertible to `bool`. `sizeof...(TTypes)` equals `sizeof...(UTypes)`.
 
 
 
803
 
804
  *Returns:* `true` if `get<i>(t) == get<i>(u)` for all `i`, otherwise
805
- `false`. For any two zero-length tuples `e` and `f`, `e == f` returns
806
- `true`.
807
 
808
- *Effects:* The elementary comparisons are performed in order from the
809
- zeroth index upwards. No comparisons or element accesses are performed
810
- after the first equality comparison that evaluates to `false`.
 
 
 
 
 
 
 
811
 
812
  ``` cpp
813
  template<class... TTypes, class... UTypes>
814
  constexpr common_comparison_category_t<synth-three-way-result<TTypes, UTypes>...>
815
  operator<=>(const tuple<TTypes...>& t, const tuple<UTypes...>& u);
 
 
 
816
  ```
817
 
818
- *Effects:* Performs a lexicographical comparison between `t` and `u`.
819
- For any two zero-length tuples `t` and `u`, `t <=> u` returns
820
- `strong_ordering::equal`. Otherwise, equivalent to:
 
 
 
 
821
 
822
  ``` cpp
823
  if (auto c = synth-three-way(get<0>(t), get<0>(u)); c != 0) return c;
824
  return $t_tail$ <=> $u_tail$;
825
  ```
826
 
827
- where `r_tail` for some tuple `r` is a tuple containing all but the
828
- first element of `r`.
 
 
 
829
 
830
  [*Note 1*: The above definition does not require `tₜₐᵢₗ` (or `uₜₐᵢₗ`)
831
- to be constructed. It may not even be possible, as `t` and `u` are not
832
- required to be copy constructible. Also, all comparison functions are
833
- short circuited; they do not perform element accesses beyond what is
834
- required to determine the result of the comparison. — *end note*]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
835
 
836
  ### Tuple traits <a id="tuple.traits">[[tuple.traits]]</a>
837
 
838
  ``` cpp
839
  template<class... Types, class Alloc>
840
  struct uses_allocator<tuple<Types...>, Alloc> : true_type { };
841
  ```
842
 
843
- *Preconditions:* `Alloc` meets the *Cpp17Allocator* requirements
844
- ([[cpp17.allocator]]).
845
 
846
  [*Note 1*: Specialization of this trait informs other library
847
  components that `tuple` can be constructed with an allocator, even
848
  though it does not have a nested `allocator_type`. — *end note*]
849
 
850
  ### Tuple specialized algorithms <a id="tuple.special">[[tuple.special]]</a>
851
 
852
  ``` cpp
853
  template<class... Types>
854
  constexpr void swap(tuple<Types...>& x, tuple<Types...>& y) noexcept(see below);
 
 
855
  ```
856
 
857
- *Constraints:* `is_swappable_v<T>` is `true` for every type `T` in
858
- `Types`.
859
 
860
- *Remarks:* The expression inside `noexcept` is equivalent to:
861
-
862
- ``` cpp
863
- noexcept(x.swap(y))
864
- ```
865
 
866
  *Effects:* As if by `x.swap(y)`.
867
 
 
 
 
 
 
 
 
11
  arguments. See  [[pairs]].
12
 
13
  ### Header `<tuple>` synopsis <a id="tuple.syn">[[tuple.syn]]</a>
14
 
15
  ``` cpp
16
+ // all freestanding
17
  #include <compare> // see [compare.syn]
18
 
19
  namespace std {
20
  // [tuple.tuple], class template tuple
21
  template<class... Types>
22
  class tuple;
23
 
24
+ // [tuple.like], concept tuple-like
25
+ template<class T>
26
+ concept tuple-like = see belownc; // exposition only
27
+ template<class T>
28
+ concept pair-like = // exposition only
29
+ tuple-like<T> && tuple_size_v<remove_cvref_t<T>> == 2;
30
+
31
+ // [tuple.common.ref], common_reference related specializations
32
+ template<exposition onlyconceptnc{tuple-like} TTuple, exposition onlyconceptnc{tuple-like} UTuple,
33
+ template<class> class TQual, template<class> class UQual>
34
+ struct basic_common_reference<TTuple, UTuple, TQual, UQual>;
35
+ template<exposition onlyconceptnc{tuple-like} TTuple, exposition onlyconceptnc{tuple-like} UTuple>
36
+ struct common_type<TTuple, UTuple>;
37
+
38
  // [tuple.creation], tuple creation functions
39
  inline constexpr unspecified ignore;
40
 
41
  template<class... TTypes>
42
  constexpr tuple<unwrap_ref_decay_t<TTypes>...> make_tuple(TTypes&&...);
 
45
  constexpr tuple<TTypes&&...> forward_as_tuple(TTypes&&...) noexcept;
46
 
47
  template<class... TTypes>
48
  constexpr tuple<TTypes&...> tie(TTypes&...) noexcept;
49
 
50
+ template<exposition onlyconceptnc{tuple-like}... Tuples>
51
  constexpr tuple<CTypes...> tuple_cat(Tuples&&...);
52
 
53
  // [tuple.apply], calling a function with a tuple of arguments
54
+ template<class F, exposition onlyconceptnc{tuple-like} Tuple>
55
+ constexpr decltype(auto) apply(F&& f, Tuple&& t) noexcept(see below);
56
 
57
+ template<class T, exposition onlyconceptnc{tuple-like} Tuple>
58
  constexpr T make_from_tuple(Tuple&& t);
59
 
60
  // [tuple.helper], tuple helper classes
61
  template<class T> struct tuple_size; // not defined
62
  template<class T> struct tuple_size<const T>;
 
91
  constexpr const T&& get(const tuple<Types...>&& t) noexcept;
92
 
93
  // [tuple.rel], relational operators
94
  template<class... TTypes, class... UTypes>
95
  constexpr bool operator==(const tuple<TTypes...>&, const tuple<UTypes...>&);
96
+ template<class... TTypes, exposition onlyconceptnc{tuple-like} UTuple>
97
+ constexpr bool operator==(const tuple<TTypes...>&, const UTuple&);
98
  template<class... TTypes, class... UTypes>
99
  constexpr common_comparison_category_t<synth-three-way-result<TTypes, UTypes>...>
100
  operator<=>(const tuple<TTypes...>&, const tuple<UTypes...>&);
101
+ template<class... TTypes, exposition onlyconceptnc{tuple-like} UTuple>
102
+ constexpr see belownc operator<=>(const tuple<TTypes...>&, const UTuple&);
103
 
104
  // [tuple.traits], allocator-related traits
105
  template<class... Types, class Alloc>
106
  struct uses_allocator<tuple<Types...>, Alloc>;
107
 
108
  // [tuple.special], specialized algorithms
109
  template<class... Types>
110
  constexpr void swap(tuple<Types...>& x, tuple<Types...>& y) noexcept(see below);
111
+ template<class... Types>
112
+ constexpr void swap(const tuple<Types...>& x, const tuple<Types...>& y) noexcept(see below);
113
 
114
  // [tuple.helper], tuple helper classes
115
  template<class T>
116
+ constexpr size_t tuple_size_v@ = tuple_size<T>::value;
117
  }
118
  ```
119
 
120
+ ### Concept <a id="tuple.like">[[tuple.like]]</a>
121
+
122
+ ``` cpp
123
+ template<class T>
124
+ concept tuple-like = see belownc; // exposition only
125
+ ```
126
+
127
+ A type `T` models and satisfies the exposition-only concept `tuple-like`
128
+ if `remove_cvref_t<T>` is a specialization of `array`, `pair`, `tuple`,
129
+ or `ranges::subrange`.
130
+
131
  ### Class template `tuple` <a id="tuple.tuple">[[tuple.tuple]]</a>
132
 
133
  ``` cpp
134
  namespace std {
135
  template<class... Types>
 
142
  constexpr explicit(see below) tuple(UTypes&&...); // only if sizeof...(Types) >= 1
143
 
144
  tuple(const tuple&) = default;
145
  tuple(tuple&&) = default;
146
 
147
+ template<class... UTypes>
148
+ constexpr explicit(see below) tuple(tuple<UTypes...>&);
149
  template<class... UTypes>
150
  constexpr explicit(see below) tuple(const tuple<UTypes...>&);
151
  template<class... UTypes>
152
  constexpr explicit(see below) tuple(tuple<UTypes...>&&);
153
+ template<class... UTypes>
154
+ constexpr explicit(see below) tuple(const tuple<UTypes...>&&);
155
 
156
+ template<class U1, class U2>
157
+ constexpr explicit(see below) tuple(pair<U1, U2>&); // only if sizeof...(Types) == 2
158
  template<class U1, class U2>
159
  constexpr explicit(see below) tuple(const pair<U1, U2>&); // only if sizeof...(Types) == 2
160
  template<class U1, class U2>
161
  constexpr explicit(see below) tuple(pair<U1, U2>&&); // only if sizeof...(Types) == 2
162
+ template<class U1, class U2>
163
+ constexpr explicit(see below) tuple(const pair<U1, U2>&&); // only if sizeof...(Types) == 2
164
+
165
+ template<tuple-like UTuple>
166
+ constexpr explicit(see below) tuple(UTuple&&);
167
 
168
  // allocator-extended constructors
169
  template<class Alloc>
170
  constexpr explicit(see below)
171
  tuple(allocator_arg_t, const Alloc& a);
 
177
  tuple(allocator_arg_t, const Alloc& a, UTypes&&...);
178
  template<class Alloc>
179
  constexpr tuple(allocator_arg_t, const Alloc& a, const tuple&);
180
  template<class Alloc>
181
  constexpr tuple(allocator_arg_t, const Alloc& a, tuple&&);
182
+ template<class Alloc, class... UTypes>
183
+ constexpr explicit(see below)
184
+ tuple(allocator_arg_t, const Alloc& a, tuple<UTypes...>&);
185
  template<class Alloc, class... UTypes>
186
  constexpr explicit(see below)
187
  tuple(allocator_arg_t, const Alloc& a, const tuple<UTypes...>&);
188
  template<class Alloc, class... UTypes>
189
  constexpr explicit(see below)
190
  tuple(allocator_arg_t, const Alloc& a, tuple<UTypes...>&&);
191
+ template<class Alloc, class... UTypes>
192
+ constexpr explicit(see below)
193
+ tuple(allocator_arg_t, const Alloc& a, const tuple<UTypes...>&&);
194
+ template<class Alloc, class U1, class U2>
195
+ constexpr explicit(see below)
196
+ tuple(allocator_arg_t, const Alloc& a, pair<U1, U2>&);
197
  template<class Alloc, class U1, class U2>
198
  constexpr explicit(see below)
199
  tuple(allocator_arg_t, const Alloc& a, const pair<U1, U2>&);
200
  template<class Alloc, class U1, class U2>
201
  constexpr explicit(see below)
202
  tuple(allocator_arg_t, const Alloc& a, pair<U1, U2>&&);
203
+ template<class Alloc, class U1, class U2>
204
+ constexpr explicit(see below)
205
+ tuple(allocator_arg_t, const Alloc& a, const pair<U1, U2>&&);
206
+
207
+ template<class Alloc, exposition onlyconceptnc{tuple-like} UTuple>
208
+ constexpr explicit(see below) tuple(allocator_arg_t, const Alloc& a, UTuple&&);
209
 
210
  // [tuple.assign], tuple assignment
211
  constexpr tuple& operator=(const tuple&);
212
+ constexpr const tuple& operator=(const tuple&) const;
213
  constexpr tuple& operator=(tuple&&) noexcept(see below);
214
+ constexpr const tuple& operator=(tuple&&) const;
215
 
216
  template<class... UTypes>
217
  constexpr tuple& operator=(const tuple<UTypes...>&);
218
+ template<class... UTypes>
219
+ constexpr const tuple& operator=(const tuple<UTypes...>&) const;
220
  template<class... UTypes>
221
  constexpr tuple& operator=(tuple<UTypes...>&&);
222
+ template<class... UTypes>
223
+ constexpr const tuple& operator=(tuple<UTypes...>&&) const;
224
 
225
  template<class U1, class U2>
226
  constexpr tuple& operator=(const pair<U1, U2>&); // only if sizeof...(Types) == 2
227
+ template<class U1, class U2>
228
+ constexpr const tuple& operator=(const pair<U1, U2>&) const;
229
+ // only if sizeof...(Types) == 2
230
  template<class U1, class U2>
231
  constexpr tuple& operator=(pair<U1, U2>&&); // only if sizeof...(Types) == 2
232
+ template<class U1, class U2>
233
+ constexpr const tuple& operator=(pair<U1, U2>&&) const; // only if sizeof...(Types) == 2
234
+
235
+ template<exposition onlyconceptnc{tuple-like} UTuple>
236
+ constexpr tuple& operator=(UTuple&&);
237
+ template<exposition onlyconceptnc{tuple-like}@ UTuple>
238
+ constexpr const tuple& operator=(UTuple&&) const;
239
 
240
  // [tuple.swap], tuple swap
241
  constexpr void swap(tuple&) noexcept(see below);
242
+ constexpr void swap(const tuple&) const noexcept(see below);
243
  };
244
 
245
  template<class... UTypes>
246
  tuple(UTypes...) -> tuple<UTypes...>;
247
  template<class T1, class T2>
 
265
  For each `tuple` constructor, an exception is thrown only if the
266
  construction of one of the types in `Types` throws an exception.
267
 
268
  The defaulted move and copy constructor, respectively, of `tuple` is a
269
  constexpr function if and only if all required element-wise
270
+ initializations for move and copy, respectively, would be
271
+ constexpr-suitable [[dcl.constexpr]]. The defaulted move and copy
272
  constructor of `tuple<>` are constexpr functions.
273
 
274
  If `is_trivially_destructible_v<Tᵢ>` is `true` for all `Tᵢ`, then the
275
  destructor of `tuple` is trivial.
276
 
277
+ The default constructor of `tuple<>` is trivial.
278
+
279
  ``` cpp
280
  constexpr explicit(see below) tuple();
281
  ```
282
 
283
  *Constraints:* `is_default_constructible_v<``Tᵢ``>` is `true` for all i.
 
309
 
310
  ``` cpp
311
  template<class... UTypes> constexpr explicit(see below) tuple(UTypes&&... u);
312
  ```
313
 
314
+ Let *disambiguating-constraint* be:
315
+
316
+ - `negation<is_same<remove_cvref_t<``U₀``>, tuple>>` if
317
+ `sizeof...(Types)` is 1;
318
+ - otherwise,
319
+ `bool_constant<!is_same_v<remove_cvref_t<``U₀``>, allocator_arg_t> || is_- same_v<remove_cvref_t<``T₀``>, allocator_arg_t>>`
320
+ if `sizeof...(Types)` is 2 or 3;
321
+ - otherwise, `true_type`.
322
+
323
+ *Constraints:*
324
+
325
+ - `sizeof...(Types)` equals `sizeof...(UTypes)`,
326
+ - `sizeof...(Types)` ≥ 1, and
327
+ - `conjunction_v<`*`disambiguating-constraint`*`, is_constructible<Types, UTypes>...>`
328
+ is `true`.
329
 
330
  *Effects:* Initializes the elements in the tuple with the corresponding
331
  value in `std::forward<UTypes>(u)`.
332
 
333
  *Remarks:* The expression inside `explicit` is equivalent to:
334
 
335
  ``` cpp
336
  !conjunction_v<is_convertible<UTypes, Types>...>
337
  ```
338
 
339
+ This constructor is defined as deleted if
340
+
341
+ ``` cpp
342
+ (reference_constructs_from_temporary_v<Types, UTypes&&> || ...)
343
+ ```
344
+
345
+ is `true`.
346
+
347
  ``` cpp
348
  tuple(const tuple& u) = default;
349
  ```
350
 
351
  *Mandates:* `is_copy_constructible_v<``Tᵢ``>` is `true` for all i.
 
361
 
362
  *Effects:* For all i, initializes the iᵗʰ element of `*this` with
363
  `std::forward<``Tᵢ``>(get<`i`>(u))`.
364
 
365
  ``` cpp
366
+ template<class... UTypes> constexpr explicit(see below) tuple(tuple<UTypes...>& u);
367
  template<class... UTypes> constexpr explicit(see below) tuple(const tuple<UTypes...>& u);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
368
  template<class... UTypes> constexpr explicit(see below) tuple(tuple<UTypes...>&& u);
369
+ template<class... UTypes> constexpr explicit(see below) tuple(const tuple<UTypes...>&& u);
370
  ```
371
 
372
+ Let `I` be the pack `0, 1, ..., (sizeof...(Types) - 1)`. Let
373
+ *`FWD`*`(u)` be `static_cast<decltype(u)>(u)`.
374
+
375
  *Constraints:*
376
 
377
  - `sizeof...(Types)` equals `sizeof...(UTypes)`, and
378
+ - `(is_constructible_v<Types, decltype(get<I>(`*`FWD`*`(u)))> && ...)`
379
+ is `true`, and
380
  - either `sizeof...(Types)` is not 1, or (when `Types...` expands to `T`
381
+ and `UTypes...` expands to `U`) `is_convertible_v<decltype(u), T>`,
382
+ `is_constructible_v<T, decltype(u)>`, and `is_same_v<T, U>` are all
383
  `false`.
384
 
385
+ *Effects:* For all i, initializes the $i^\textrm{th}$ element of `*this`
386
+ with `get<`i`>(`*`FWD`*`(u))`.
387
 
388
  *Remarks:* The expression inside `explicit` is equivalent to:
389
 
390
  ``` cpp
391
+ !(is_convertible_v<decltype(get<I>(FWD(u))), Types> && ...)
392
  ```
393
 
394
+ The constructor is defined as deleted if
395
+
396
+ ``` cpp
397
+ (reference_constructs_from_temporary_v<Types, decltype(get<I>(FWD(u)))> || ...)
398
+ ```
399
+
400
+ is `true`.
401
+
402
  ``` cpp
403
+ template<class U1, class U2> constexpr explicit(see below) tuple(pair<U1, U2>& u);
404
  template<class U1, class U2> constexpr explicit(see below) tuple(const pair<U1, U2>& u);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
405
  template<class U1, class U2> constexpr explicit(see below) tuple(pair<U1, U2>&& u);
406
+ template<class U1, class U2> constexpr explicit(see below) tuple(const pair<U1, U2>&& u);
407
  ```
408
 
409
+ Let *`FWD`*`(u)` be `static_cast<decltype(u)>(u)`.
410
+
411
  *Constraints:*
412
 
413
  - `sizeof...(Types)` is 2,
414
+ - `is_constructible_v<``T₀``, decltype(get<0>(`*`FWD`*`(u)))>` is
415
+ `true`, and
416
+ - `is_constructible_v<``T₁``, decltype(get<1>(`*`FWD`*`(u)))>` is
417
+ `true`.
418
 
419
+ *Effects:* Initializes the first element with `get<0>(`*`FWD`*`(u))` and
420
+ the second element with `get<1>(`*`FWD`*`(u))`.
 
421
 
422
+ *Remarks:* The expression inside `explicit` is equivalent to:
423
 
424
  ``` cpp
425
+ !is_convertible_v<decltype(get<0>(FWD(u))), $T_0$> ||
426
+ !is_convertible_v<decltype(get<1>(FWD(u))), $T_1$>
427
+ ```
428
+
429
+ The constructor is defined as deleted if
430
+
431
+ ``` cpp
432
+ reference_constructs_from_temporary_v<$T_0$, decltype(get<0>(FWD(u)))> ||
433
+ reference_constructs_from_temporary_v<$T_1$, decltype(get<1>(FWD(u)))>
434
+ ```
435
+
436
+ is `true`.
437
+
438
+ ``` cpp
439
+ template<tuple-like UTuple>
440
+ constexpr explicit(see below) tuple(UTuple&& u);
441
+ ```
442
+
443
+ Let `I` be the pack `0, 1, …, (sizeof...(Types) - 1)`.
444
+
445
+ *Constraints:*
446
+
447
+ - `different-from<UTuple, tuple>` [[range.utility.helpers]] is `true`,
448
+ - `remove_cvref_t<UTuple>` is not a specialization of
449
+ `ranges::subrange`,
450
+ - `sizeof...(Types)` equals `tuple_size_v<remove_cvref_t<UTuple>>`,
451
+ - `(is_constructible_v<Types, decltype(get<I>(std::forward<UTuple>(u)))> && ...)`
452
+ is `true`, and
453
+ - either `sizeof...(Types)` is not `1`, or (when `Types...` expands to
454
+ `T`) `is_convertible_v<UTuple, T>` and `is_constructible_v<T, UTuple>`
455
+ are both `false`.
456
+
457
+ *Effects:* For all i, initializes the iᵗʰ element of `*this` with
458
+ `get<`i`>(std::forward<UTuple>(u))`.
459
+
460
+ *Remarks:* The expression inside `explicit` is equivalent to:
461
+
462
+ ``` cpp
463
+ !(is_convertible_v<decltype(get<I>(std::forward<UTuple>(u))), Types> && ...)
464
  ```
465
 
466
  ``` cpp
467
  template<class Alloc>
468
  constexpr explicit(see below)
 
475
  tuple(allocator_arg_t, const Alloc& a, UTypes&&...);
476
  template<class Alloc>
477
  constexpr tuple(allocator_arg_t, const Alloc& a, const tuple&);
478
  template<class Alloc>
479
  constexpr tuple(allocator_arg_t, const Alloc& a, tuple&&);
480
+ template<class Alloc, class... UTypes>
481
+ constexpr explicit(see below)
482
+ tuple(allocator_arg_t, const Alloc& a, tuple<UTypes...>&);
483
  template<class Alloc, class... UTypes>
484
  constexpr explicit(see below)
485
  tuple(allocator_arg_t, const Alloc& a, const tuple<UTypes...>&);
486
  template<class Alloc, class... UTypes>
487
  constexpr explicit(see below)
488
  tuple(allocator_arg_t, const Alloc& a, tuple<UTypes...>&&);
489
+ template<class Alloc, class... UTypes>
490
+ constexpr explicit(see below)
491
+ tuple(allocator_arg_t, const Alloc& a, const tuple<UTypes...>&&);
492
+ template<class Alloc, class U1, class U2>
493
+ constexpr explicit(see below)
494
+ tuple(allocator_arg_t, const Alloc& a, pair<U1, U2>&);
495
  template<class Alloc, class U1, class U2>
496
  constexpr explicit(see below)
497
  tuple(allocator_arg_t, const Alloc& a, const pair<U1, U2>&);
498
  template<class Alloc, class U1, class U2>
499
  constexpr explicit(see below)
500
  tuple(allocator_arg_t, const Alloc& a, pair<U1, U2>&&);
501
+ template<class Alloc, class U1, class U2>
502
+ constexpr explicit(see below)
503
+ tuple(allocator_arg_t, const Alloc& a, const pair<U1, U2>&&);
504
+ template<class Alloc, tuple-like UTuple>
505
+ constexpr explicit(see below)
506
+ tuple(allocator_arg_t, const Alloc& a, UTuple&&);
507
  ```
508
 
509
+ *Preconditions:* `Alloc` meets the *Cpp17Allocator*
510
+ requirements [[allocator.requirements.general]].
511
 
512
  *Effects:* Equivalent to the preceding constructors except that each
513
  element is constructed with uses-allocator
514
  construction [[allocator.uses.construction]].
515
 
 
527
  ```
528
 
529
  *Effects:* Assigns each element of `u` to the corresponding element of
530
  `*this`.
531
 
532
+ *Returns:* `*this`.
533
+
534
  *Remarks:* This operator is defined as deleted unless
535
  `is_copy_assignable_v<``Tᵢ``>` is `true` for all i.
536
 
537
+ ``` cpp
538
+ constexpr const tuple& operator=(const tuple& u) const;
539
+ ```
540
+
541
+ *Constraints:* `(is_copy_assignable_v<const Types> && ...)` is `true`.
542
+
543
+ *Effects:* Assigns each element of `u` to the corresponding element of
544
+ `*this`.
545
+
546
  *Returns:* `*this`.
547
 
548
  ``` cpp
549
  constexpr tuple& operator=(tuple&& u) noexcept(see below);
550
  ```
 
552
  *Constraints:* `is_move_assignable_v<``Tᵢ``>` is `true` for all i.
553
 
554
  *Effects:* For all i, assigns `std::forward<``Tᵢ``>(get<`i`>(u))` to
555
  `get<`i`>(*this)`.
556
 
557
+ *Returns:* `*this`.
558
+
559
+ *Remarks:* The exception specification is equivalent to the logical of
560
+ the following expressions:
561
 
562
  ``` cpp
563
  is_nothrow_move_assignable_v<Tᵢ>
564
  ```
565
 
566
  where Tᵢ is the iᵗʰ type in `Types`.
567
 
568
+ ``` cpp
569
+ constexpr const tuple& operator=(tuple&& u) const;
570
+ ```
571
+
572
+ *Constraints:* `(is_assignable_v<const Types&, Types> && ...)` is
573
+ `true`.
574
+
575
+ *Effects:* For all i, assigns `std::forward<T`ᵢ`>(get<`i`>(u))` to
576
+ `get<`i`>(*this)`.
577
+
578
  *Returns:* `*this`.
579
 
580
  ``` cpp
581
  template<class... UTypes> constexpr tuple& operator=(const tuple<UTypes...>& u);
582
  ```
 
589
  *Effects:* Assigns each element of `u` to the corresponding element of
590
  `*this`.
591
 
592
  *Returns:* `*this`.
593
 
594
+ ``` cpp
595
+ template<class... UTypes> constexpr const tuple& operator=(const tuple<UTypes...>& u) const;
596
+ ```
597
+
598
+ *Constraints:*
599
+
600
+ - `sizeof...(Types)` equals `sizeof...(UTypes)` and
601
+ - `(is_assignable_v<const Types&, const UTypes&> && ...)` is `true`.
602
+
603
+ *Effects:* Assigns each element of `u` to the corresponding element of
604
+ `*this`.
605
+
606
+ *Returns:* `*this`.
607
+
608
  ``` cpp
609
  template<class... UTypes> constexpr tuple& operator=(tuple<UTypes...>&& u);
610
  ```
611
 
612
  *Constraints:*
 
617
  *Effects:* For all i, assigns `std::forward<``Uᵢ``>(get<`i`>(u))` to
618
  `get<`i`>(*this)`.
619
 
620
  *Returns:* `*this`.
621
 
622
+ ``` cpp
623
+ template<class... UTypes> constexpr const tuple& operator=(tuple<UTypes...>&& u) const;
624
+ ```
625
+
626
+ *Constraints:*
627
+
628
+ - `sizeof...(Types)` equals `sizeof...(UTypes)` and
629
+ - `(is_assignable_v<const Types&, UTypes> && ...)` is `true`.
630
+
631
+ *Effects:* For all i, assigns `std::forward<U`ᵢ`>(get<`i`>(u))` to
632
+ `get<`i`>(*this)`.
633
+
634
+ *Returns:* `*this`.
635
+
636
  ``` cpp
637
  template<class U1, class U2> constexpr tuple& operator=(const pair<U1, U2>& u);
638
  ```
639
 
640
  *Constraints:*
 
646
  *Effects:* Assigns `u.first` to the first element of `*this` and
647
  `u.second` to the second element of `*this`.
648
 
649
  *Returns:* `*this`.
650
 
651
+ ``` cpp
652
+ template<class U1, class U2> constexpr const tuple& operator=(const pair<U1, U2>& u) const;
653
+ ```
654
+
655
+ *Constraints:*
656
+
657
+ - `sizeof...(Types)` is 2,
658
+ - `is_assignable_v<const ``T₀``&, const U1&>` is `true`, and
659
+ - `is_assignable_v<const ``T₁``&, const U2&>` is `true`.
660
+
661
+ *Effects:* Assigns `u.first` to the first element and `u.second` to the
662
+ second element.
663
+
664
+ *Returns:* `*this`.
665
+
666
  ``` cpp
667
  template<class U1, class U2> constexpr tuple& operator=(pair<U1, U2>&& u);
668
  ```
669
 
670
  *Constraints:*
 
677
  `*this` and
678
  `std::forward<U2>(u.second)` to the second element of `*this`.
679
 
680
  *Returns:* `*this`.
681
 
682
+ ``` cpp
683
+ template<class U1, class U2> constexpr const tuple& operator=(pair<U1, U2>&& u) const;
684
+ ```
685
+
686
+ *Constraints:*
687
+
688
+ - `sizeof...(Types)` is 2,
689
+ - `is_assignable_v<const ``T₀``&, U1>` is `true`, and
690
+ - `is_assignable_v<const ``T₁``&, U2>` is `true`.
691
+
692
+ *Effects:* Assigns `std::forward<U1>(u.first)` to the first element
693
+ and
694
+ `std::forward<U2>(u.second)` to the second element.
695
+
696
+ *Returns:* `*this`.
697
+
698
+ ``` cpp
699
+ template<tuple-like UTuple>
700
+ constexpr tuple& operator=(UTuple&& u);
701
+ ```
702
+
703
+ *Constraints:*
704
+
705
+ - `different-from<UTuple, tuple>` [[range.utility.helpers]] is `true`,
706
+ - `remove_cvref_t<UTuple>` is not a specialization of
707
+ `ranges::subrange`,
708
+ - `sizeof...(Types)` equals `tuple_size_v<remove_cvref_t<UTuple>>`, and,
709
+ - `is_assignable_v<``Tᵢ``&, decltype(get<`i`>(std::forward<UTuple>(u)))>`
710
+ is `true` for all i.
711
+
712
+ *Effects:* For all i, assigns `get<`i`>(std::forward<UTuple>(u))` to
713
+ `get<`i`>(*this)`.
714
+
715
+ *Returns:* `*this`.
716
+
717
+ ``` cpp
718
+ template<tuple-like UTuple>
719
+ constexpr const tuple& operator=(UTuple&& u) const;
720
+ ```
721
+
722
+ *Constraints:*
723
+
724
+ - `different-from<UTuple, tuple>` [[range.utility.helpers]] is `true`,
725
+ - `remove_cvref_t<UTuple>` is not a specialization of
726
+ `ranges::subrange`,
727
+ - `sizeof...(Types)` equals `tuple_size_v<remove_cvref_t<UTuple>>`, and,
728
+ - `is_assignable_v<const ``Tᵢ``&, decltype(get<`i`>(std::forward<UTuple>(u)))>`
729
+ is `true` for all i.
730
+
731
+ *Effects:* For all i, assigns `get<`i`>(std::forward<UTuple>(u))` to
732
+ `get<`i`>(*this)`.
733
+
734
+ *Returns:* `*this`.
735
+
736
  #### `swap` <a id="tuple.swap">[[tuple.swap]]</a>
737
 
738
  ``` cpp
739
  constexpr void swap(tuple& rhs) noexcept(see below);
740
+ constexpr void swap(const tuple& rhs) const noexcept(see below);
741
  ```
742
 
743
+ Let i be in the range \[`0`, `sizeof...(Types)`) in order.
 
744
 
745
+ *Mandates:*
 
746
 
747
+ - For the first overload, `(is_swappable_v<Types> && ...)` is `true`.
748
+ - For the second overload, `(is_swappable_v<const Types> && ...)` is
749
+ `true`.
750
 
751
+ *Preconditions:* For all i, `get<`i`>(*this)` is swappable
752
+ with [[swappable.requirements]] `get<`i`>(rhs)`.
 
753
 
754
+ *Effects:* For each i, calls `swap` for `get<`i`>(*this)` with
755
+ `get<`i`>(rhs)`.
756
 
757
  *Throws:* Nothing unless one of the element-wise `swap` calls throws an
758
  exception.
759
 
760
+ *Remarks:* The exception specification is equivalent to
761
+
762
+ - `(is_nothrow_swappable_v<Types> && ...)` for the first overload and
763
+ - `(is_nothrow_swappable_v<const Types> && ...)` for the second
764
+ overload.
765
+
766
  ### Tuple creation functions <a id="tuple.creation">[[tuple.creation]]</a>
767
 
 
 
 
 
768
  ``` cpp
769
  template<class... TTypes>
770
  constexpr tuple<unwrap_ref_decay_t<TTypes>...> make_tuple(TTypes&&... t);
771
  ```
772
 
 
775
 
776
  [*Example 1*:
777
 
778
  ``` cpp
779
  int i; float j;
780
+ make_tuple(1, ref(i), cref(j));
781
  ```
782
 
783
  creates a tuple of type `tuple<int, int&, const float&>`.
784
 
785
  — *end example*]
 
819
  ```
820
 
821
  — *end example*]
822
 
823
  ``` cpp
824
+ template<tuple-like... Tuples>
825
  constexpr tuple<CTypes...> tuple_cat(Tuples&&... tpls);
826
  ```
827
 
828
+ Let n be `sizeof...(Tuples)`. For every integer 0 i < n:
 
 
829
 
830
+ - Let `Tᵢ` be the iᵗʰ type in `Tuples`.
831
+ - Let `Uᵢ` be `remove_cvref_t<``Tᵢ``>`.
832
+ - Let `tpᵢ` be the iᵗʰ element in the function parameter pack `tpls`.
833
+ - Let Sᵢ be `tuple_size_v<``Uᵢ``>`.
834
+ - Let Eᵢᵏ be `tuple_element_t<`k`, ``Uᵢ``>`.
835
+ - Let eᵢᵏ be `get<`k`>(std::forward<``Tᵢ``>(``tpᵢ``))`.
836
+ - Let Elemsᵢ be a pack of the types $E_i^0, \dotsc, E_i^{S_{i-1}}$.
837
+ - Let elemsᵢ be a pack of the expressions
838
+ $e_i^0, \dotsc, e_i^{S_{i-1}}$.
839
 
840
+ The types in `CTypes` are equal to the ordered sequence of the expanded
841
+ packs of types Elems₀`...`, Elems₁`...`, …, Elemsₙ₋₁`...`. Let `celems`
842
+ be the ordered sequence of the expanded packs of expressions
843
+ elems₀`...`, …, elemsₙ₋₁`...`.
844
 
845
+ *Mandates:* `(is_constructible_v<CTypes, decltype(celems)> && ...)` is
846
+ `true`.
 
 
 
847
 
848
+ *Returns:* `tuple<CTypes...>(celems...)`.
 
 
 
 
 
 
 
 
 
 
 
849
 
850
  ### Calling a function with a `tuple` of arguments <a id="tuple.apply">[[tuple.apply]]</a>
851
 
852
  ``` cpp
853
+ template<class F, tuple-like Tuple>
854
+ constexpr decltype(auto) apply(F&& f, Tuple&& t) noexcept(see below);
855
  ```
856
 
857
  *Effects:* Given the exposition-only function:
858
 
859
  ``` cpp
860
+ namespace std {
861
+ template<class F, tuple-like Tuple, size_t... I>
862
  constexpr decltype(auto) apply-impl(F&& f, Tuple&& t, index_sequence<I...>) {
863
  // exposition only
864
+ return INVOKE(std::forward<F>(f), get<I>(std::forward<Tuple>(t))...); // see [func.require]
865
+ }
866
  }
867
  ```
868
 
869
  Equivalent to:
870
 
871
  ``` cpp
872
  return apply-impl(std::forward<F>(f), std::forward<Tuple>(t),
873
  make_index_sequence<tuple_size_v<remove_reference_t<Tuple>>>{});
874
  ```
875
 
876
+ *Remarks:* Let `I` be the pack
877
+ `0, 1, ..., (tuple_size_v<remove_reference_t<Tuple>> - 1)`. The
878
+ exception specification is equivalent to:
879
+
880
  ``` cpp
881
+ noexcept(invoke(std::forward<F>(f), get<I>(std::forward<Tuple>(t))...))
882
+ ```
883
+
884
+ ``` cpp
885
+ template<class T, tuple-like Tuple>
886
  constexpr T make_from_tuple(Tuple&& t);
887
  ```
888
 
889
+ *Mandates:* If `tuple_size_v<remove_reference_t<Tuple>>` is 1, then
890
+ `reference_constructs_from_temporary_v<T, decltype(get<0>(declval<Tuple>()))>`
891
+ is `false`.
892
+
893
  *Effects:* Given the exposition-only function:
894
 
895
  ``` cpp
896
+ namespace std {
897
+ template<class T, tuple-like Tuple, size_t... I>
898
+ requires is_constructible_v<T, decltype(get<I>(declval<Tuple>()))...>
899
  constexpr T make-from-tuple-impl(Tuple&& t, index_sequence<I...>) { // exposition only
900
  return T(get<I>(std::forward<Tuple>(t))...);
901
  }
902
+ }
903
  ```
904
 
905
  Equivalent to:
906
 
907
  ``` cpp
908
  return make-from-tuple-impl<T>(
909
+ std::forward<Tuple>(t),
910
  make_index_sequence<tuple_size_v<remove_reference_t<Tuple>>>{});
911
  ```
912
 
913
  [*Note 1*: The type of `T` must be supplied as an explicit template
914
  parameter, as it cannot be deduced from the argument
 
945
  template<class T> struct tuple_size<const T>;
946
  ```
947
 
948
  Let `TS` denote `tuple_size<T>` of the cv-unqualified type `T`. If the
949
  expression `TS::value` is well-formed when treated as an unevaluated
950
+ operand [[term.unevaluated.operand]], then each specialization of the
951
+ template meets the *Cpp17UnaryTypeTrait* requirements [[meta.rqmts]]
952
+ with a base characteristic of
953
 
954
  ``` cpp
955
  integral_constant<size_t, TS::value>
956
  ```
957
 
 
1011
 
1012
  [*Note 2*: \[Note B\]Constness is shallow. If a type `T` in `Types` is
1013
  some reference type `X&`, the return type is `X&`, not `const X&`.
1014
  However, if the element type is a non-reference type `T`, the return
1015
  type is `const T&`. This is consistent with how constness is defined to
1016
+ work for non-static data members of reference type. — *end note*]
1017
 
1018
  ``` cpp
1019
  template<class T, class... Types>
1020
  constexpr T& get(tuple<Types...>& t) noexcept;
1021
  template<class T, class... Types>
 
1050
  ### Relational operators <a id="tuple.rel">[[tuple.rel]]</a>
1051
 
1052
  ``` cpp
1053
  template<class... TTypes, class... UTypes>
1054
  constexpr bool operator==(const tuple<TTypes...>& t, const tuple<UTypes...>& u);
1055
+ template<class... TTypes, tuple-like UTuple>
1056
+ constexpr bool operator==(const tuple<TTypes...>& t, const UTuple& u);
1057
  ```
1058
 
1059
+ For the first overload let `UTuple` be `tuple<UTypes...>`.
1060
+
1061
  *Mandates:* For all `i`, where 0 ≤ `i` < `sizeof...(TTypes)`,
1062
+ `get<i>(t) == get<i>(u)` is a valid expression. `sizeof...(TTypes)`
1063
+ equals `tuple_size_v<UTuple>`.
1064
+
1065
+ *Preconditions:* For all `i`, `decltype(get<i>(t) == get<i>(u))` models
1066
+ `boolean-testable`.
1067
 
1068
  *Returns:* `true` if `get<i>(t) == get<i>(u)` for all `i`, otherwise
1069
+ `false`.
 
1070
 
1071
+ [*Note 1*: If `sizeof...(TTypes)` equals zero, returns
1072
+ `true`. *end note*]
1073
+
1074
+ *Remarks:*
1075
+
1076
+ - The elementary comparisons are performed in order from the zeroth
1077
+ index upwards. No comparisons or element accesses are performed after
1078
+ the first equality comparison that evaluates to `false`.
1079
+ - The second overload is to be found via argument-dependent
1080
+ lookup [[basic.lookup.argdep]] only.
1081
 
1082
  ``` cpp
1083
  template<class... TTypes, class... UTypes>
1084
  constexpr common_comparison_category_t<synth-three-way-result<TTypes, UTypes>...>
1085
  operator<=>(const tuple<TTypes...>& t, const tuple<UTypes...>& u);
1086
+ template<class... TTypes, tuple-like UTuple>
1087
+ constexpr common_comparison_category_t<synth-three-way-result<TTypes, Elems>...>
1088
+ operator<=>(const tuple<TTypes...>& t, const UTuple& u);
1089
  ```
1090
 
1091
+ For the second overload, `Elems` denotes the pack of types
1092
+ `tuple_element_t<0, UTuple>`, `tuple_element_t<1, UTuple>`, …,
1093
+ `tuple_element_t<tuple_size_v<UTuple> - 1, UTuple>`.
1094
+
1095
+ *Effects:* Performs a lexicographical comparison between `t` and `u`. If
1096
+ `sizeof...(TTypes)` equals zero, returns `strong_ordering::equal`.
1097
+ Otherwise, equivalent to:
1098
 
1099
  ``` cpp
1100
  if (auto c = synth-three-way(get<0>(t), get<0>(u)); c != 0) return c;
1101
  return $t_tail$ <=> $u_tail$;
1102
  ```
1103
 
1104
+ where `r_tail` for some `r` is a tuple containing all but the first
1105
+ element of `r`.
1106
+
1107
+ *Remarks:* The second overload is to be found via argument-dependent
1108
+ lookup [[basic.lookup.argdep]] only.
1109
 
1110
  [*Note 1*: The above definition does not require `tₜₐᵢₗ` (or `uₜₐᵢₗ`)
1111
+ to be constructed. It might not even be possible, as `t` and `u` are not
1112
+ required to be copy constructible. Also, all comparison operator
1113
+ functions are short circuited; they do not perform element accesses
1114
+ beyond what is required to determine the result of the
1115
+ comparison. — *end note*]
1116
+
1117
+ ### `common_reference` related specializations <a id="tuple.common.ref">[[tuple.common.ref]]</a>
1118
+
1119
+ In the descriptions that follow:
1120
+
1121
+ - Let `TTypes` be a pack formed by the sequence of
1122
+ `tuple_element_t<i, TTuple>` for every integer
1123
+ 0 ≤ i < `tuple_size_v<TTuple>`.
1124
+ - Let `UTypes` be a pack formed by the sequence of
1125
+ `tuple_element_t<i, UTuple>` for every integer
1126
+ 0 ≤ i < `tuple_size_v<UTuple>`.
1127
+
1128
+ ``` cpp
1129
+ template<tuple-like TTuple, tuple-like UTuple,
1130
+ template<class> class TQual, template<class> class UQual>
1131
+ struct basic_common_reference<TTuple, UTuple, TQual, UQual> {
1132
+ using type = see below;
1133
+ };
1134
+ ```
1135
+
1136
+ *Constraints:*
1137
+
1138
+ - `TTuple` is a specialization of `tuple` or `UTuple` is a
1139
+ specialization of `tuple`.
1140
+ - `is_same_v<TTuple, decay_t<TTuple>>` is `true`.
1141
+ - `is_same_v<UTuple, decay_t<UTuple>>` is `true`.
1142
+ - `tuple_size_v<TTuple>` equals `tuple_size_v<UTuple>`.
1143
+ - `tuple<common_reference_t<TQual<TTypes>, UQual<UTypes>>...>` denotes a
1144
+ type.
1145
+
1146
+ The member *typedef-name* `type` denotes the type
1147
+ `tuple<common_reference_t<TQual<TTypes>, UQual<UTypes>>...>`.
1148
+
1149
+ ``` cpp
1150
+ template<tuple-like TTuple, tuple-like UTuple>
1151
+ struct common_type<TTuple, UTuple> {
1152
+ using type = see below;
1153
+ };
1154
+ ```
1155
+
1156
+ *Constraints:*
1157
+
1158
+ - `TTuple` is a specialization of `tuple` or `UTuple` is a
1159
+ specialization of `tuple`.
1160
+ - `is_same_v<TTuple, decay_t<TTuple>>` is `true`.
1161
+ - `is_same_v<UTuple, decay_t<UTuple>>` is `true`.
1162
+ - `tuple_size_v<TTuple>` equals `tuple_size_v<UTuple>`.
1163
+ - `tuple<common_type_t<TTypes, UTypes>...>` denotes a type.
1164
+
1165
+ The member *typedef-name* `type` denotes the type
1166
+ `tuple<common_type_t<TTypes, UTypes>...>`.
1167
 
1168
  ### Tuple traits <a id="tuple.traits">[[tuple.traits]]</a>
1169
 
1170
  ``` cpp
1171
  template<class... Types, class Alloc>
1172
  struct uses_allocator<tuple<Types...>, Alloc> : true_type { };
1173
  ```
1174
 
1175
+ *Preconditions:* `Alloc` meets the *Cpp17Allocator*
1176
+ requirements [[allocator.requirements.general]].
1177
 
1178
  [*Note 1*: Specialization of this trait informs other library
1179
  components that `tuple` can be constructed with an allocator, even
1180
  though it does not have a nested `allocator_type`. — *end note*]
1181
 
1182
  ### Tuple specialized algorithms <a id="tuple.special">[[tuple.special]]</a>
1183
 
1184
  ``` cpp
1185
  template<class... Types>
1186
  constexpr void swap(tuple<Types...>& x, tuple<Types...>& y) noexcept(see below);
1187
+ template<class... Types>
1188
+ constexpr void swap(const tuple<Types...>& x, const tuple<Types...>& y) noexcept(see below);
1189
  ```
1190
 
1191
+ *Constraints:*
 
1192
 
1193
+ - For the first overload, `(is_swappable_v<Types> && ...)` is `true`.
1194
+ - For the second overload, `(is_swappable_v<const Types> && ...)` is
1195
+ `true`.
 
 
1196
 
1197
  *Effects:* As if by `x.swap(y)`.
1198
 
1199
+ *Remarks:* The exception specification is equivalent to:
1200
+
1201
+ ``` cpp
1202
+ noexcept(x.swap(y))
1203
+ ```
1204
+