From Jason Turner

[cmp]

Diff to HTML by rtfpessoa

Files changed (1) hide show
  1. tmp/tmp7l6llzaq/{from.md → to.md} +76 -54
tmp/tmp7l6llzaq/{from.md → to.md} RENAMED
@@ -5,10 +5,11 @@
5
  The header `<compare>` specifies types, objects, and functions for use
6
  primarily in connection with the three-way comparison operator
7
  [[expr.spaceship]].
8
 
9
  ``` cpp
 
10
  namespace std {
11
  // [cmp.categories], comparison category types
12
  class partial_ordering;
13
  class weak_ordering;
14
  class strong_ordering;
@@ -65,13 +66,11 @@ collectively termed the *comparison category types*. Each is specified
65
  in terms of an exposition-only data member named `value` whose value
66
  typically corresponds to that of an enumerator from one of the following
67
  exposition-only enumerations:
68
 
69
  ``` cpp
70
- enum class eq { equal = 0, equivalent = equal,
71
- nonequal = 1, nonequivalent = nonequal }; // exposition only
72
- enum class ord { less = -1, greater = 1 }; // exposition only
73
  enum class ncmp { unordered = -127 }; // exposition only
74
  ```
75
 
76
  [*Note 1*: The type `strong_ordering` corresponds to the term total
77
  ordering in mathematics. — *end note*]
@@ -98,24 +97,22 @@ where `f` denotes a function that reads only comparison-salient state
98
  that is accessible via the argument’s public const members.
99
 
100
  #### Class `partial_ordering` <a id="cmp.partialord">[[cmp.partialord]]</a>
101
 
102
  The `partial_ordering` type is typically used as the result type of a
103
- three-way comparison operator [[expr.spaceship]] that (a) admits all of
104
- the six two-way comparison operators ([[expr.rel]], [[expr.eq]]), (b)
105
- does not imply substitutability, and (c) permits two values to be
106
- incomparable. [^34]
107
 
108
  ``` cpp
109
  namespace std {
110
  class partial_ordering {
111
  int value; // exposition only
112
  bool is_ordered; // exposition only
113
 
114
  // exposition-only constructors
115
- constexpr explicit
116
- partial_ordering(eq v) noexcept : value(int(v)), is_ordered(true) {} // exposition only
117
  constexpr explicit
118
  partial_ordering(ord v) noexcept : value(int(v)), is_ordered(true) {} // exposition only
119
  constexpr explicit
120
  partial_ordering(ncmp v) noexcept : value(int(v)), is_ordered(false) {} // exposition only
121
 
@@ -141,11 +138,11 @@ namespace std {
141
  friend constexpr partial_ordering operator<=>(unspecified, partial_ordering v) noexcept;
142
  };
143
 
144
  // valid values' definitions
145
  inline constexpr partial_ordering partial_ordering::less(ord::less);
146
- inline constexpr partial_ordering partial_ordering::equivalent(eq::equivalent);
147
  inline constexpr partial_ordering partial_ordering::greater(ord::greater);
148
  inline constexpr partial_ordering partial_ordering::unordered(ncmp::unordered);
149
  }
150
  ```
151
 
@@ -182,21 +179,20 @@ constexpr partial_ordering operator<=>(unspecified, partial_ordering v) noexcept
182
  `v < 0 ? partial_ordering::greater : v > 0 ? partial_ordering::less : v`.
183
 
184
  #### Class `weak_ordering` <a id="cmp.weakord">[[cmp.weakord]]</a>
185
 
186
  The `weak_ordering` type is typically used as the result type of a
187
- three-way comparison operator [[expr.spaceship]] that (a) admits all of
188
- the six two-way comparison operators ([[expr.rel]], [[expr.eq]]), and
189
- (b) does not imply substitutability.
190
 
191
  ``` cpp
192
  namespace std {
193
  class weak_ordering {
194
  int value; // exposition only
195
 
196
  // exposition-only constructors
197
- constexpr explicit weak_ordering(eq v) noexcept : value(int(v)) {} // exposition only
198
  constexpr explicit weak_ordering(ord v) noexcept : value(int(v)) {} // exposition only
199
 
200
  public:
201
  // valid values
202
  static const weak_ordering less;
@@ -221,11 +217,11 @@ namespace std {
221
  friend constexpr weak_ordering operator<=>(unspecified, weak_ordering v) noexcept;
222
  };
223
 
224
  // valid values' definitions
225
  inline constexpr weak_ordering weak_ordering::less(ord::less);
226
- inline constexpr weak_ordering weak_ordering::equivalent(eq::equivalent);
227
  inline constexpr weak_ordering weak_ordering::greater(ord::greater);
228
  }
229
  ```
230
 
231
  ``` cpp
@@ -273,21 +269,20 @@ constexpr weak_ordering operator<=>(unspecified, weak_ordering v) noexcept;
273
  `v < 0 ? weak_ordering::greater : v > 0 ? weak_ordering::less : v`.
274
 
275
  #### Class `strong_ordering` <a id="cmp.strongord">[[cmp.strongord]]</a>
276
 
277
  The `strong_ordering` type is typically used as the result type of a
278
- three-way comparison operator [[expr.spaceship]] that (a) admits all of
279
- the six two-way comparison operators ([[expr.rel]], [[expr.eq]]), and
280
- (b) does imply substitutability.
281
 
282
  ``` cpp
283
  namespace std {
284
  class strong_ordering {
285
  int value; // exposition only
286
 
287
  // exposition-only constructors
288
- constexpr explicit strong_ordering(eq v) noexcept : value(int(v)) {} // exposition only
289
  constexpr explicit strong_ordering(ord v) noexcept : value(int(v)) {} // exposition only
290
 
291
  public:
292
  // valid values
293
  static const strong_ordering less;
@@ -314,12 +309,12 @@ namespace std {
314
  friend constexpr strong_ordering operator<=>(unspecified, strong_ordering v) noexcept;
315
  };
316
 
317
  // valid values' definitions
318
  inline constexpr strong_ordering strong_ordering::less(ord::less);
319
- inline constexpr strong_ordering strong_ordering::equal(eq::equal);
320
- inline constexpr strong_ordering strong_ordering::equivalent(eq::equivalent);
321
  inline constexpr strong_ordering strong_ordering::greater(ord::greater);
322
  }
323
  ```
324
 
325
  ``` cpp
@@ -401,11 +396,11 @@ pack, or `void` if any element of `Ts` is not a comparison category
401
  type.
402
 
403
  [*Note 1*: This is `std::strong_ordering` if the expansion is
404
  empty. — *end note*]
405
 
406
- ### Concept `three_way_comparable` <a id="cmp.concept">[[cmp.concept]]</a>
407
 
408
  ``` cpp
409
  template<class T, class Cat>
410
  concept compares-as = // exposition only
411
  same_as<common_comparison_category_t<T, Cat>, Cat>;
@@ -461,32 +456,37 @@ and `Cat` model `three_way_comparable<T, Cat>` only if:
461
  ``` cpp
462
  template<class T, class U, class Cat = partial_ordering>
463
  concept three_way_comparable_with =
464
  three_way_comparable<T, Cat> &&
465
  three_way_comparable<U, Cat> &&
466
- common_reference_with<const remove_reference_t<T>&, const remove_reference_t<U>&> &&
467
  three_way_comparable<
468
  common_reference_t<const remove_reference_t<T>&, const remove_reference_t<U>&>, Cat> &&
469
  weakly-equality-comparable-with<T, U> &&
470
  partially-ordered-with<T, U> &&
471
  requires(const remove_reference_t<T>& t, const remove_reference_t<U>& u) {
472
  { t <=> u } -> compares-as<Cat>;
473
  { u <=> t } -> compares-as<Cat>;
474
  };
475
  ```
476
 
477
- Let `t` and `u` be lvalues of types `const remove_reference_t<T>` and
478
- `const remove_reference_t<U>`, respectively. Let `C` be
 
 
 
479
  `common_reference_t<const remove_reference_t<T>&, const remove_reference_t<U>&>`.
480
- `T`, `U`, and `Cat` model `three_way_comparable_with<T, U, Cat>` only
481
- if:
 
482
 
483
  - `t <=> u` and `u <=> t` have the same domain,
484
  - `((t <=> u) <=> 0)` and `(0 <=> (u <=> t))` are equal,
485
  - `(t <=> u == 0) == bool(t == u)` is `true`,
486
  - `(t <=> u != 0) == bool(t != u)` is `true`,
487
- - `Cat(t <=> u) == Cat(C(t) <=> C(u))` is `true`,
 
488
  - `(t <=> u < 0) == bool(t < u)` is `true`,
489
  - `(t <=> u > 0) == bool(t > u)` is `true`,
490
  - `(t <=> u <= 0) == bool(t <= u)` is `true`,
491
  - `(t <=> u >= 0) == bool(t >= u)` is `true`, and
492
  - if `Cat` is convertible to `strong_ordering`, `T` and `U` model
@@ -509,38 +509,41 @@ member `type`.
509
  ### Comparison algorithms <a id="cmp.alg">[[cmp.alg]]</a>
510
 
511
  The name `strong_order` denotes a customization point object
512
  [[customization.point.object]]. Given subexpressions `E` and `F`, the
513
  expression `strong_order(E, F)` is expression-equivalent
514
- [[defns.expression-equivalent]] to the following:
515
 
516
  - If the decayed types of `E` and `F` differ, `strong_order(E, F)` is
517
  ill-formed.
518
  - Otherwise, `strong_ordering(strong_order(E, F))` if it is a
519
- well-formed expression with overload resolution performed in a context
520
- that does not include a declaration of `std::strong_order`.
 
521
  - Otherwise, if the decayed type `T` of `E` is a floating-point type,
522
  yields a value of type `strong_ordering` that is consistent with the
523
  ordering observed by `T`’s comparison operators, and if
524
  `numeric_limits<T>::is_iec559` is `true`, is additionally consistent
525
  with the `totalOrder` operation as specified in ISO/IEC/IEEE 60559.
526
  - Otherwise, `strong_ordering(compare_three_way()(E, F))` if it is a
527
  well-formed expression.
528
- - Otherwise, `strong_order(E, F)` is ill-formed. \[*Note 1*: This case
529
- can result in substitution failure when `strong_order(E, F)` appears
530
- in the immediate context of a template instantiation. *end note*]
 
 
531
 
532
  The name `weak_order` denotes a customization point object
533
  [[customization.point.object]]. Given subexpressions `E` and `F`, the
534
  expression `weak_order(E, F)` is expression-equivalent
535
- [[defns.expression-equivalent]] to the following:
536
 
537
  - If the decayed types of `E` and `F` differ, `weak_order(E, F)` is
538
  ill-formed.
539
  - Otherwise, `weak_ordering(weak_order(E, F))` if it is a well-formed
540
- expression with overload resolution performed in a context that does
541
- not include a declaration of `std::weak_order`.
542
  - Otherwise, if the decayed type `T` of `E` is a floating-point type,
543
  yields a value of type `weak_ordering` that is consistent with the
544
  ordering observed by `T`’s comparison operators and `strong_order`,
545
  and if `numeric_limits<T>::is_iec559` is `true`, is additionally
546
  consistent with the following equivalence classes, ordered from lesser
@@ -556,86 +559,105 @@ expression `weak_order(E, F)` is expression-equivalent
556
  - together, all positive NaN values.
557
  - Otherwise, `weak_ordering(compare_three_way()(E, F))` if it is a
558
  well-formed expression.
559
  - Otherwise, `weak_ordering(strong_order(E, F))` if it is a well-formed
560
  expression.
561
- - Otherwise, `weak_order(E, F)` is ill-formed. \[*Note 2*: This case can
562
- result in substitution failure when `std::weak_order(E, F)` appears in
563
- the immediate context of a template instantiation. *end note*]
 
 
564
 
565
  The name `partial_order` denotes a customization point object
566
  [[customization.point.object]]. Given subexpressions `E` and `F`, the
567
  expression `partial_order(E, F)` is expression-equivalent
568
- [[defns.expression-equivalent]] to the following:
569
 
570
  - If the decayed types of `E` and `F` differ, `partial_order(E, F)` is
571
  ill-formed.
572
  - Otherwise, `partial_ordering(partial_order(E, F))` if it is a
573
- well-formed expression with overload resolution performed in a context
574
- that does not include a declaration of `std::partial_order`.
 
575
  - Otherwise, `partial_ordering(compare_three_way()(E, F))` if it is a
576
  well-formed expression.
577
  - Otherwise, `partial_ordering(weak_order(E, F))` if it is a well-formed
578
  expression.
579
- - Otherwise, `partial_order(E, F)` is ill-formed. \[*Note 3*: This case
580
- can result in substitution failure when `std::partial_order(E, F)`
581
- appears in the immediate context of a template
 
582
  instantiation. — *end note*]
583
 
584
  The name `compare_strong_order_fallback` denotes a customization point
585
- object [[customization.point.object]]. Given subexpressions `E` and F,
586
  the expression `compare_strong_order_fallback(E, F)` is
587
- expression-equivalent [[defns.expression-equivalent]] to:
588
 
589
  - If the decayed types of `E` and `F` differ,
590
  `compare_strong_order_fallback(E, F)` is ill-formed.
591
  - Otherwise, `strong_order(E, F)` if it is a well-formed expression.
592
  - Otherwise, if the expressions `E == F` and `E < F` are both
593
- well-formed and convertible to `bool`,
 
594
  ``` cpp
595
  E == F ? strong_ordering::equal :
596
  E < F ? strong_ordering::less :
597
  strong_ordering::greater
598
  ```
599
 
600
  except that `E` and `F` are evaluated only once.
601
  - Otherwise, `compare_strong_order_fallback(E, F)` is ill-formed.
602
 
 
 
 
 
603
  The name `compare_weak_order_fallback` denotes a customization point
604
  object [[customization.point.object]]. Given subexpressions `E` and `F`,
605
  the expression `compare_weak_order_fallback(E, F)` is
606
- expression-equivalent [[defns.expression-equivalent]] to:
607
 
608
  - If the decayed types of `E` and `F` differ,
609
  `compare_weak_order_fallback(E, F)` is ill-formed.
610
  - Otherwise, `weak_order(E, F)` if it is a well-formed expression.
611
  - Otherwise, if the expressions `E == F` and `E < F` are both
612
- well-formed and convertible to `bool`,
 
613
  ``` cpp
614
  E == F ? weak_ordering::equivalent :
615
  E < F ? weak_ordering::less :
616
  weak_ordering::greater
617
  ```
618
 
619
  except that `E` and `F` are evaluated only once.
620
  - Otherwise, `compare_weak_order_fallback(E, F)` is ill-formed.
621
 
 
 
 
 
622
  The name `compare_partial_order_fallback` denotes a customization point
623
  object [[customization.point.object]]. Given subexpressions `E` and `F`,
624
  the expression `compare_partial_order_fallback(E, F)` is
625
- expression-equivalent [[defns.expression-equivalent]] to:
626
 
627
  - If the decayed types of `E` and `F` differ,
628
  `compare_partial_order_fallback(E, F)` is ill-formed.
629
  - Otherwise, `partial_order(E, F)` if it is a well-formed expression.
630
- - Otherwise, if the expressions `E == F` and `E < F` are both
631
- well-formed and convertible to `bool`,
 
632
  ``` cpp
633
  E == F ? partial_ordering::equivalent :
634
  E < F ? partial_ordering::less :
635
  F < E ? partial_ordering::greater :
636
  partial_ordering::unordered
637
  ```
638
 
639
  except that `E` and `F` are evaluated only once.
640
  - Otherwise, `compare_partial_order_fallback(E, F)` is ill-formed.
641
 
 
 
 
 
 
5
  The header `<compare>` specifies types, objects, and functions for use
6
  primarily in connection with the three-way comparison operator
7
  [[expr.spaceship]].
8
 
9
  ``` cpp
10
+ // all freestanding
11
  namespace std {
12
  // [cmp.categories], comparison category types
13
  class partial_ordering;
14
  class weak_ordering;
15
  class strong_ordering;
 
66
  in terms of an exposition-only data member named `value` whose value
67
  typically corresponds to that of an enumerator from one of the following
68
  exposition-only enumerations:
69
 
70
  ``` cpp
71
+ enum class ord { equal = 0, equivalent = equal, less = -1, greater = 1 }; // exposition only
 
 
72
  enum class ncmp { unordered = -127 }; // exposition only
73
  ```
74
 
75
  [*Note 1*: The type `strong_ordering` corresponds to the term total
76
  ordering in mathematics. — *end note*]
 
97
  that is accessible via the argument’s public const members.
98
 
99
  #### Class `partial_ordering` <a id="cmp.partialord">[[cmp.partialord]]</a>
100
 
101
  The `partial_ordering` type is typically used as the result type of a
102
+ three-way comparison operator [[expr.spaceship]] for a type that admits
103
+ all of the six two-way comparison operators [[expr.rel]], [[expr.eq]],
104
+ for which equality need not imply substitutability, and that permits two
105
+ values to be incomparable.[^32]
106
 
107
  ``` cpp
108
  namespace std {
109
  class partial_ordering {
110
  int value; // exposition only
111
  bool is_ordered; // exposition only
112
 
113
  // exposition-only constructors
 
 
114
  constexpr explicit
115
  partial_ordering(ord v) noexcept : value(int(v)), is_ordered(true) {} // exposition only
116
  constexpr explicit
117
  partial_ordering(ncmp v) noexcept : value(int(v)), is_ordered(false) {} // exposition only
118
 
 
138
  friend constexpr partial_ordering operator<=>(unspecified, partial_ordering v) noexcept;
139
  };
140
 
141
  // valid values' definitions
142
  inline constexpr partial_ordering partial_ordering::less(ord::less);
143
+ inline constexpr partial_ordering partial_ordering::equivalent(ord::equivalent);
144
  inline constexpr partial_ordering partial_ordering::greater(ord::greater);
145
  inline constexpr partial_ordering partial_ordering::unordered(ncmp::unordered);
146
  }
147
  ```
148
 
 
179
  `v < 0 ? partial_ordering::greater : v > 0 ? partial_ordering::less : v`.
180
 
181
  #### Class `weak_ordering` <a id="cmp.weakord">[[cmp.weakord]]</a>
182
 
183
  The `weak_ordering` type is typically used as the result type of a
184
+ three-way comparison operator [[expr.spaceship]] for a type that admits
185
+ all of the six two-way comparison operators [[expr.rel]], [[expr.eq]]
186
+ and for which equality need not imply substitutability.
187
 
188
  ``` cpp
189
  namespace std {
190
  class weak_ordering {
191
  int value; // exposition only
192
 
193
  // exposition-only constructors
 
194
  constexpr explicit weak_ordering(ord v) noexcept : value(int(v)) {} // exposition only
195
 
196
  public:
197
  // valid values
198
  static const weak_ordering less;
 
217
  friend constexpr weak_ordering operator<=>(unspecified, weak_ordering v) noexcept;
218
  };
219
 
220
  // valid values' definitions
221
  inline constexpr weak_ordering weak_ordering::less(ord::less);
222
+ inline constexpr weak_ordering weak_ordering::equivalent(ord::equivalent);
223
  inline constexpr weak_ordering weak_ordering::greater(ord::greater);
224
  }
225
  ```
226
 
227
  ``` cpp
 
269
  `v < 0 ? weak_ordering::greater : v > 0 ? weak_ordering::less : v`.
270
 
271
  #### Class `strong_ordering` <a id="cmp.strongord">[[cmp.strongord]]</a>
272
 
273
  The `strong_ordering` type is typically used as the result type of a
274
+ three-way comparison operator [[expr.spaceship]] for a type that admits
275
+ all of the six two-way comparison operators [[expr.rel]], [[expr.eq]]
276
+ and for which equality does imply substitutability.
277
 
278
  ``` cpp
279
  namespace std {
280
  class strong_ordering {
281
  int value; // exposition only
282
 
283
  // exposition-only constructors
 
284
  constexpr explicit strong_ordering(ord v) noexcept : value(int(v)) {} // exposition only
285
 
286
  public:
287
  // valid values
288
  static const strong_ordering less;
 
309
  friend constexpr strong_ordering operator<=>(unspecified, strong_ordering v) noexcept;
310
  };
311
 
312
  // valid values' definitions
313
  inline constexpr strong_ordering strong_ordering::less(ord::less);
314
+ inline constexpr strong_ordering strong_ordering::equal(ord::equal);
315
+ inline constexpr strong_ordering strong_ordering::equivalent(ord::equivalent);
316
  inline constexpr strong_ordering strong_ordering::greater(ord::greater);
317
  }
318
  ```
319
 
320
  ``` cpp
 
396
  type.
397
 
398
  [*Note 1*: This is `std::strong_ordering` if the expansion is
399
  empty. — *end note*]
400
 
401
+ ### Concept <a id="cmp.concept">[[cmp.concept]]</a>
402
 
403
  ``` cpp
404
  template<class T, class Cat>
405
  concept compares-as = // exposition only
406
  same_as<common_comparison_category_t<T, Cat>, Cat>;
 
456
  ``` cpp
457
  template<class T, class U, class Cat = partial_ordering>
458
  concept three_way_comparable_with =
459
  three_way_comparable<T, Cat> &&
460
  three_way_comparable<U, Cat> &&
461
+ comparison-common-type-with<T, U> &&
462
  three_way_comparable<
463
  common_reference_t<const remove_reference_t<T>&, const remove_reference_t<U>&>, Cat> &&
464
  weakly-equality-comparable-with<T, U> &&
465
  partially-ordered-with<T, U> &&
466
  requires(const remove_reference_t<T>& t, const remove_reference_t<U>& u) {
467
  { t <=> u } -> compares-as<Cat>;
468
  { u <=> t } -> compares-as<Cat>;
469
  };
470
  ```
471
 
472
+ Let `t` and `t2` be lvalues denoting distinct equal objects of types
473
+ `const remove_reference_t<T>` and `remove_cvref_t<T>`, respectively, and
474
+ let `u` and `u2` be lvalues denoting distinct equal objects of types
475
+ `const remove_reference_t<U>` and `remove_cvref_t<U>`, respectively. Let
476
+ `C` be
477
  `common_reference_t<const remove_reference_t<T>&, const remove_reference_t<U>&>`.
478
+ Let `CONVERT_TO_LVALUE<C>(E)` be defined as in
479
+ [[concepts.compare.general]]. `T`, `U`, and `Cat` model
480
+ `three_way_comparable_with<T, U, Cat>` only if:
481
 
482
  - `t <=> u` and `u <=> t` have the same domain,
483
  - `((t <=> u) <=> 0)` and `(0 <=> (u <=> t))` are equal,
484
  - `(t <=> u == 0) == bool(t == u)` is `true`,
485
  - `(t <=> u != 0) == bool(t != u)` is `true`,
486
+ - `Cat(t <=> u) == Cat(CONVERT_TO_LVALUE<C>(t2) <=>
487
+ CONVERT_TO_LVALUE<C>(u2))` is `true`,
488
  - `(t <=> u < 0) == bool(t < u)` is `true`,
489
  - `(t <=> u > 0) == bool(t > u)` is `true`,
490
  - `(t <=> u <= 0) == bool(t <= u)` is `true`,
491
  - `(t <=> u >= 0) == bool(t >= u)` is `true`, and
492
  - if `Cat` is convertible to `strong_ordering`, `T` and `U` model
 
509
  ### Comparison algorithms <a id="cmp.alg">[[cmp.alg]]</a>
510
 
511
  The name `strong_order` denotes a customization point object
512
  [[customization.point.object]]. Given subexpressions `E` and `F`, the
513
  expression `strong_order(E, F)` is expression-equivalent
514
+ [[defns.expression.equivalent]] to the following:
515
 
516
  - If the decayed types of `E` and `F` differ, `strong_order(E, F)` is
517
  ill-formed.
518
  - Otherwise, `strong_ordering(strong_order(E, F))` if it is a
519
+ well-formed expression where the meaning of `strong_order` is
520
+ established as-if by performing argument-dependent lookup only
521
+ [[basic.lookup.argdep]].
522
  - Otherwise, if the decayed type `T` of `E` is a floating-point type,
523
  yields a value of type `strong_ordering` that is consistent with the
524
  ordering observed by `T`’s comparison operators, and if
525
  `numeric_limits<T>::is_iec559` is `true`, is additionally consistent
526
  with the `totalOrder` operation as specified in ISO/IEC/IEEE 60559.
527
  - Otherwise, `strong_ordering(compare_three_way()(E, F))` if it is a
528
  well-formed expression.
529
+ - Otherwise, `strong_order(E, F)` is ill-formed.
530
+
531
+ [*Note 1*: Ill-formed cases above result in substitution failure when
532
+ `strong_order(E, F)` appears in the immediate context of a template
533
+ instantiation. — *end note*]
534
 
535
  The name `weak_order` denotes a customization point object
536
  [[customization.point.object]]. Given subexpressions `E` and `F`, the
537
  expression `weak_order(E, F)` is expression-equivalent
538
+ [[defns.expression.equivalent]] to the following:
539
 
540
  - If the decayed types of `E` and `F` differ, `weak_order(E, F)` is
541
  ill-formed.
542
  - Otherwise, `weak_ordering(weak_order(E, F))` if it is a well-formed
543
+ expression where the meaning of `weak_order` is established as-if by
544
+ performing argument-dependent lookup only [[basic.lookup.argdep]].
545
  - Otherwise, if the decayed type `T` of `E` is a floating-point type,
546
  yields a value of type `weak_ordering` that is consistent with the
547
  ordering observed by `T`’s comparison operators and `strong_order`,
548
  and if `numeric_limits<T>::is_iec559` is `true`, is additionally
549
  consistent with the following equivalence classes, ordered from lesser
 
559
  - together, all positive NaN values.
560
  - Otherwise, `weak_ordering(compare_three_way()(E, F))` if it is a
561
  well-formed expression.
562
  - Otherwise, `weak_ordering(strong_order(E, F))` if it is a well-formed
563
  expression.
564
+ - Otherwise, `weak_order(E, F)` is ill-formed.
565
+
566
+ [*Note 2*: Ill-formed cases above result in substitution failure when
567
+ `weak_order(E, F)` appears in the immediate context of a template
568
+ instantiation. — *end note*]
569
 
570
  The name `partial_order` denotes a customization point object
571
  [[customization.point.object]]. Given subexpressions `E` and `F`, the
572
  expression `partial_order(E, F)` is expression-equivalent
573
+ [[defns.expression.equivalent]] to the following:
574
 
575
  - If the decayed types of `E` and `F` differ, `partial_order(E, F)` is
576
  ill-formed.
577
  - Otherwise, `partial_ordering(partial_order(E, F))` if it is a
578
+ well-formed expression where the meaning of `partial_order` is
579
+ established as-if by performing argument-dependent lookup only
580
+ [[basic.lookup.argdep]].
581
  - Otherwise, `partial_ordering(compare_three_way()(E, F))` if it is a
582
  well-formed expression.
583
  - Otherwise, `partial_ordering(weak_order(E, F))` if it is a well-formed
584
  expression.
585
+ - Otherwise, `partial_order(E, F)` is ill-formed.
586
+
587
+ [*Note 3*: Ill-formed cases above result in substitution failure when
588
+ `partial_order(E, F)` appears in the immediate context of a template
589
  instantiation. — *end note*]
590
 
591
  The name `compare_strong_order_fallback` denotes a customization point
592
+ object [[customization.point.object]]. Given subexpressions `E` and `F`,
593
  the expression `compare_strong_order_fallback(E, F)` is
594
+ expression-equivalent [[defns.expression.equivalent]] to:
595
 
596
  - If the decayed types of `E` and `F` differ,
597
  `compare_strong_order_fallback(E, F)` is ill-formed.
598
  - Otherwise, `strong_order(E, F)` if it is a well-formed expression.
599
  - Otherwise, if the expressions `E == F` and `E < F` are both
600
+ well-formed and each of `decltype(E == F)` and `decltype(E < F)`
601
+ models `boolean-testable`,
602
  ``` cpp
603
  E == F ? strong_ordering::equal :
604
  E < F ? strong_ordering::less :
605
  strong_ordering::greater
606
  ```
607
 
608
  except that `E` and `F` are evaluated only once.
609
  - Otherwise, `compare_strong_order_fallback(E, F)` is ill-formed.
610
 
611
+ [*Note 4*: Ill-formed cases above result in substitution failure when
612
+ `compare_strong_order_fallback(E, F)` appears in the immediate context
613
+ of a template instantiation. — *end note*]
614
+
615
  The name `compare_weak_order_fallback` denotes a customization point
616
  object [[customization.point.object]]. Given subexpressions `E` and `F`,
617
  the expression `compare_weak_order_fallback(E, F)` is
618
+ expression-equivalent [[defns.expression.equivalent]] to:
619
 
620
  - If the decayed types of `E` and `F` differ,
621
  `compare_weak_order_fallback(E, F)` is ill-formed.
622
  - Otherwise, `weak_order(E, F)` if it is a well-formed expression.
623
  - Otherwise, if the expressions `E == F` and `E < F` are both
624
+ well-formed and each of `decltype(E == F)` and `decltype(E < F)`
625
+ models `boolean-testable`,
626
  ``` cpp
627
  E == F ? weak_ordering::equivalent :
628
  E < F ? weak_ordering::less :
629
  weak_ordering::greater
630
  ```
631
 
632
  except that `E` and `F` are evaluated only once.
633
  - Otherwise, `compare_weak_order_fallback(E, F)` is ill-formed.
634
 
635
+ [*Note 5*: Ill-formed cases above result in substitution failure when
636
+ `compare_weak_order_fallback(E, F)` appears in the immediate context of
637
+ a template instantiation. — *end note*]
638
+
639
  The name `compare_partial_order_fallback` denotes a customization point
640
  object [[customization.point.object]]. Given subexpressions `E` and `F`,
641
  the expression `compare_partial_order_fallback(E, F)` is
642
+ expression-equivalent [[defns.expression.equivalent]] to:
643
 
644
  - If the decayed types of `E` and `F` differ,
645
  `compare_partial_order_fallback(E, F)` is ill-formed.
646
  - Otherwise, `partial_order(E, F)` if it is a well-formed expression.
647
+ - Otherwise, if the expressions `E == F`, `E < F`, and `F < E` are all
648
+ well-formed and each of `decltype(E == F)` and `decltype(E < F)`
649
+ models `boolean-testable`,
650
  ``` cpp
651
  E == F ? partial_ordering::equivalent :
652
  E < F ? partial_ordering::less :
653
  F < E ? partial_ordering::greater :
654
  partial_ordering::unordered
655
  ```
656
 
657
  except that `E` and `F` are evaluated only once.
658
  - Otherwise, `compare_partial_order_fallback(E, F)` is ill-formed.
659
 
660
+ [*Note 6*: Ill-formed cases above result in substitution failure when
661
+ `compare_partial_order_fallback(E, F)` appears in the immediate context
662
+ of a template instantiation. — *end note*]
663
+