From Jason Turner

[cmp]

Diff to HTML by rtfpessoa

Files changed (1) hide show
  1. tmp/tmpqv7xx49l/{from.md → to.md} +641 -0
tmp/tmpqv7xx49l/{from.md → to.md} RENAMED
@@ -0,0 +1,641 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## Comparisons <a id="cmp">[[cmp]]</a>
2
+
3
+ ### Header `<compare>` synopsis <a id="compare.syn">[[compare.syn]]</a>
4
+
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;
15
+
16
+ // named comparison functions
17
+ constexpr bool is_eq (partial_ordering cmp) noexcept { return cmp == 0; }
18
+ constexpr bool is_neq (partial_ordering cmp) noexcept { return cmp != 0; }
19
+ constexpr bool is_lt (partial_ordering cmp) noexcept { return cmp < 0; }
20
+ constexpr bool is_lteq(partial_ordering cmp) noexcept { return cmp <= 0; }
21
+ constexpr bool is_gt (partial_ordering cmp) noexcept { return cmp > 0; }
22
+ constexpr bool is_gteq(partial_ordering cmp) noexcept { return cmp >= 0; }
23
+
24
+ // [cmp.common], common comparison category type
25
+ template<class... Ts>
26
+ struct common_comparison_category {
27
+ using type = see below;
28
+ };
29
+ template<class... Ts>
30
+ using common_comparison_category_t = typename common_comparison_category<Ts...>::type;
31
+
32
+ // [cmp.concept], concept three_way_comparable
33
+ template<class T, class Cat = partial_ordering>
34
+ concept three_way_comparable = see below;
35
+ template<class T, class U, class Cat = partial_ordering>
36
+ concept three_way_comparable_with = see below;
37
+
38
+ // [cmp.result], result of three-way comparison
39
+ template<class T, class U = T> struct compare_three_way_result;
40
+
41
+ template<class T, class U = T>
42
+ using compare_three_way_result_t = typename compare_three_way_result<T, U>::type;
43
+
44
+ // [comparisons.three.way], class compare_three_way
45
+ struct compare_three_way;
46
+
47
+ // [cmp.alg], comparison algorithms
48
+ inline namespace unspecified {
49
+ inline constexpr unspecified strong_order = unspecified;
50
+ inline constexpr unspecified weak_order = unspecified;
51
+ inline constexpr unspecified partial_order = unspecified;
52
+ inline constexpr unspecified compare_strong_order_fallback = unspecified;
53
+ inline constexpr unspecified compare_weak_order_fallback = unspecified;
54
+ inline constexpr unspecified compare_partial_order_fallback = unspecified;
55
+ }
56
+ }
57
+ ```
58
+
59
+ ### Comparison category types <a id="cmp.categories">[[cmp.categories]]</a>
60
+
61
+ #### Preamble <a id="cmp.categories.pre">[[cmp.categories.pre]]</a>
62
+
63
+ The types `partial_ordering`, `weak_ordering`, and `strong_ordering` are
64
+ 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*]
78
+
79
+ The relational and equality operators for the comparison category types
80
+ are specified with an anonymous parameter of unspecified type. This type
81
+ shall be selected by the implementation such that these parameters can
82
+ accept literal `0` as a corresponding argument.
83
+
84
+ [*Example 1*:
85
+
86
+ `nullptr_t`
87
+
88
+ meets this requirement.
89
+
90
+ — *end example*]
91
+
92
+ In this context, the behavior of a program that supplies an argument
93
+ other than a literal `0` is undefined.
94
+
95
+ For the purposes of subclause [[cmp.categories]], *substitutability* is
96
+ the property that `f(a) == f(b)` is `true` whenever `a == b` is `true`,
97
+ 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
+
122
+ public:
123
+ // valid values
124
+ static const partial_ordering less;
125
+ static const partial_ordering equivalent;
126
+ static const partial_ordering greater;
127
+ static const partial_ordering unordered;
128
+
129
+ // comparisons
130
+ friend constexpr bool operator==(partial_ordering v, unspecified) noexcept;
131
+ friend constexpr bool operator==(partial_ordering v, partial_ordering w) noexcept = default;
132
+ friend constexpr bool operator< (partial_ordering v, unspecified) noexcept;
133
+ friend constexpr bool operator> (partial_ordering v, unspecified) noexcept;
134
+ friend constexpr bool operator<=(partial_ordering v, unspecified) noexcept;
135
+ friend constexpr bool operator>=(partial_ordering v, unspecified) noexcept;
136
+ friend constexpr bool operator< (unspecified, partial_ordering v) noexcept;
137
+ friend constexpr bool operator> (unspecified, partial_ordering v) noexcept;
138
+ friend constexpr bool operator<=(unspecified, partial_ordering v) noexcept;
139
+ friend constexpr bool operator>=(unspecified, partial_ordering v) noexcept;
140
+ friend constexpr partial_ordering operator<=>(partial_ordering v, unspecified) noexcept;
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
+
152
+ ``` cpp
153
+ constexpr bool operator==(partial_ordering v, unspecified) noexcept;
154
+ constexpr bool operator< (partial_ordering v, unspecified) noexcept;
155
+ constexpr bool operator> (partial_ordering v, unspecified) noexcept;
156
+ constexpr bool operator<=(partial_ordering v, unspecified) noexcept;
157
+ constexpr bool operator>=(partial_ordering v, unspecified) noexcept;
158
+ ```
159
+
160
+ *Returns:* For `operator`, `v.is_ordered && v.value 0`.
161
+
162
+ ``` cpp
163
+ constexpr bool operator< (unspecified, partial_ordering v) noexcept;
164
+ constexpr bool operator> (unspecified, partial_ordering v) noexcept;
165
+ constexpr bool operator<=(unspecified, partial_ordering v) noexcept;
166
+ constexpr bool operator>=(unspecified, partial_ordering v) noexcept;
167
+ ```
168
+
169
+ *Returns:* For `operator`, `v.is_ordered && 0 v.value`.
170
+
171
+ ``` cpp
172
+ constexpr partial_ordering operator<=>(partial_ordering v, unspecified) noexcept;
173
+ ```
174
+
175
+ *Returns:* `v`.
176
+
177
+ ``` cpp
178
+ constexpr partial_ordering operator<=>(unspecified, partial_ordering v) noexcept;
179
+ ```
180
+
181
+ *Returns:*
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;
203
+ static const weak_ordering equivalent;
204
+ static const weak_ordering greater;
205
+
206
+ // conversions
207
+ constexpr operator partial_ordering() const noexcept;
208
+
209
+ // comparisons
210
+ friend constexpr bool operator==(weak_ordering v, unspecified) noexcept;
211
+ friend constexpr bool operator==(weak_ordering v, weak_ordering w) noexcept = default;
212
+ friend constexpr bool operator< (weak_ordering v, unspecified) noexcept;
213
+ friend constexpr bool operator> (weak_ordering v, unspecified) noexcept;
214
+ friend constexpr bool operator<=(weak_ordering v, unspecified) noexcept;
215
+ friend constexpr bool operator>=(weak_ordering v, unspecified) noexcept;
216
+ friend constexpr bool operator< (unspecified, weak_ordering v) noexcept;
217
+ friend constexpr bool operator> (unspecified, weak_ordering v) noexcept;
218
+ friend constexpr bool operator<=(unspecified, weak_ordering v) noexcept;
219
+ friend constexpr bool operator>=(unspecified, weak_ordering v) noexcept;
220
+ friend constexpr weak_ordering operator<=>(weak_ordering v, unspecified) noexcept;
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
232
+ constexpr operator partial_ordering() const noexcept;
233
+ ```
234
+
235
+ *Returns:*
236
+
237
+ ``` cpp
238
+ value == 0 ? partial_ordering::equivalent :
239
+ value < 0 ? partial_ordering::less :
240
+ partial_ordering::greater
241
+ ```
242
+
243
+ ``` cpp
244
+ constexpr bool operator==(weak_ordering v, unspecified) noexcept;
245
+ constexpr bool operator< (weak_ordering v, unspecified) noexcept;
246
+ constexpr bool operator> (weak_ordering v, unspecified) noexcept;
247
+ constexpr bool operator<=(weak_ordering v, unspecified) noexcept;
248
+ constexpr bool operator>=(weak_ordering v, unspecified) noexcept;
249
+ ```
250
+
251
+ *Returns:* `v.value 0` for `operator`.
252
+
253
+ ``` cpp
254
+ constexpr bool operator< (unspecified, weak_ordering v) noexcept;
255
+ constexpr bool operator> (unspecified, weak_ordering v) noexcept;
256
+ constexpr bool operator<=(unspecified, weak_ordering v) noexcept;
257
+ constexpr bool operator>=(unspecified, weak_ordering v) noexcept;
258
+ ```
259
+
260
+ *Returns:* `0 v.value` for `operator`.
261
+
262
+ ``` cpp
263
+ constexpr weak_ordering operator<=>(weak_ordering v, unspecified) noexcept;
264
+ ```
265
+
266
+ *Returns:* `v`.
267
+
268
+ ``` cpp
269
+ constexpr weak_ordering operator<=>(unspecified, weak_ordering v) noexcept;
270
+ ```
271
+
272
+ *Returns:*
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;
294
+ static const strong_ordering equal;
295
+ static const strong_ordering equivalent;
296
+ static const strong_ordering greater;
297
+
298
+ // conversions
299
+ constexpr operator partial_ordering() const noexcept;
300
+ constexpr operator weak_ordering() const noexcept;
301
+
302
+ // comparisons
303
+ friend constexpr bool operator==(strong_ordering v, unspecified) noexcept;
304
+ friend constexpr bool operator==(strong_ordering v, strong_ordering w) noexcept = default;
305
+ friend constexpr bool operator< (strong_ordering v, unspecified) noexcept;
306
+ friend constexpr bool operator> (strong_ordering v, unspecified) noexcept;
307
+ friend constexpr bool operator<=(strong_ordering v, unspecified) noexcept;
308
+ friend constexpr bool operator>=(strong_ordering v, unspecified) noexcept;
309
+ friend constexpr bool operator< (unspecified, strong_ordering v) noexcept;
310
+ friend constexpr bool operator> (unspecified, strong_ordering v) noexcept;
311
+ friend constexpr bool operator<=(unspecified, strong_ordering v) noexcept;
312
+ friend constexpr bool operator>=(unspecified, strong_ordering v) noexcept;
313
+ friend constexpr strong_ordering operator<=>(strong_ordering v, unspecified) noexcept;
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
326
+ constexpr operator partial_ordering() const noexcept;
327
+ ```
328
+
329
+ *Returns:*
330
+
331
+ ``` cpp
332
+ value == 0 ? partial_ordering::equivalent :
333
+ value < 0 ? partial_ordering::less :
334
+ partial_ordering::greater
335
+ ```
336
+
337
+ ``` cpp
338
+ constexpr operator weak_ordering() const noexcept;
339
+ ```
340
+
341
+ *Returns:*
342
+
343
+ ``` cpp
344
+ value == 0 ? weak_ordering::equivalent :
345
+ value < 0 ? weak_ordering::less :
346
+ weak_ordering::greater
347
+ ```
348
+
349
+ ``` cpp
350
+ constexpr bool operator==(strong_ordering v, unspecified) noexcept;
351
+ constexpr bool operator< (strong_ordering v, unspecified) noexcept;
352
+ constexpr bool operator> (strong_ordering v, unspecified) noexcept;
353
+ constexpr bool operator<=(strong_ordering v, unspecified) noexcept;
354
+ constexpr bool operator>=(strong_ordering v, unspecified) noexcept;
355
+ ```
356
+
357
+ *Returns:* `v.value 0` for `operator`.
358
+
359
+ ``` cpp
360
+ constexpr bool operator< (unspecified, strong_ordering v) noexcept;
361
+ constexpr bool operator> (unspecified, strong_ordering v) noexcept;
362
+ constexpr bool operator<=(unspecified, strong_ordering v) noexcept;
363
+ constexpr bool operator>=(unspecified, strong_ordering v) noexcept;
364
+ ```
365
+
366
+ *Returns:* `0 v.value` for `operator`.
367
+
368
+ ``` cpp
369
+ constexpr strong_ordering operator<=>(strong_ordering v, unspecified) noexcept;
370
+ ```
371
+
372
+ *Returns:* `v`.
373
+
374
+ ``` cpp
375
+ constexpr strong_ordering operator<=>(unspecified, strong_ordering v) noexcept;
376
+ ```
377
+
378
+ *Returns:*
379
+ `v < 0 ? strong_ordering::greater : v > 0 ? strong_ordering::less : v`.
380
+
381
+ ### Class template `common_comparison_category` <a id="cmp.common">[[cmp.common]]</a>
382
+
383
+ The type `common_comparison_category` provides an alias for the
384
+ strongest comparison category to which all of the template arguments can
385
+ be converted.
386
+
387
+ [*Note 1*: A comparison category type is stronger than another if they
388
+ are distinct types and an instance of the former can be converted to an
389
+ instance of the latter. — *end note*]
390
+
391
+ ``` cpp
392
+ template<class... Ts>
393
+ struct common_comparison_category {
394
+ using type = see below;
395
+ };
396
+ ```
397
+
398
+ *Remarks:* The member *typedef-name* `type` denotes the common
399
+ comparison type [[class.spaceship]] of `Ts...`, the expanded parameter
400
+ 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>;
412
+
413
+ template<class T, class U>
414
+ concept partially-ordered-with = // exposition only
415
+ requires(const remove_reference_t<T>& t, const remove_reference_t<U>& u) {
416
+ { t < u } -> boolean-testable;
417
+ { t > u } -> boolean-testable;
418
+ { t <= u } -> boolean-testable;
419
+ { t >= u } -> boolean-testable;
420
+ { u < t } -> boolean-testable;
421
+ { u > t } -> boolean-testable;
422
+ { u <= t } -> boolean-testable;
423
+ { u >= t } -> boolean-testable;
424
+ };
425
+ ```
426
+
427
+ Let `t` and `u` be lvalues of types `const remove_reference_t<T>` and
428
+ `const remove_reference_t<U>`, respectively. `T` and `U` model
429
+ `partially-ordered-with<T, U>` only if:
430
+
431
+ - `t < u`, `t <= u`, `t > u`, `t >= u`, `u < t`, `u <= t`, `u > t`, and
432
+ `u >= t` have the same domain.
433
+ - `bool(t < u) == bool(u > t)` is `true`,
434
+ - `bool(u < t) == bool(t > u)` is `true`,
435
+ - `bool(t <= u) == bool(u >= t)` is `true`, and
436
+ - `bool(u <= t) == bool(t >= u)` is `true`.
437
+
438
+ ``` cpp
439
+ template<class T, class Cat = partial_ordering>
440
+ concept three_way_comparable =
441
+ weakly-equality-comparable-with<T, T> &&
442
+ partially-ordered-with<T, T> &&
443
+ requires(const remove_reference_t<T>& a, const remove_reference_t<T>& b) {
444
+ { a <=> b } -> compares-as<Cat>;
445
+ };
446
+ ```
447
+
448
+ Let `a` and `b` be lvalues of type `const remove_reference_t<T>`. `T`
449
+ and `Cat` model `three_way_comparable<T, Cat>` only if:
450
+
451
+ - `(a <=> b == 0) == bool(a == b)` is `true`,
452
+ - `(a <=> b != 0) == bool(a != b)` is `true`,
453
+ - `((a <=> b) <=> 0)` and `(0 <=> (b <=> a))` are equal,
454
+ - `(a <=> b < 0) == bool(a < b)` is `true`,
455
+ - `(a <=> b > 0) == bool(a > b)` is `true`,
456
+ - `(a <=> b <= 0) == bool(a <= b)` is `true`,
457
+ - `(a <=> b >= 0) == bool(a >= b)` is `true`, and
458
+ - if `Cat` is convertible to `strong_ordering`, `T` models
459
+ `totally_ordered` [[concept.totallyordered]].
460
+
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
493
+ `totally_ordered_with<T, U>` [[concept.totallyordered]].
494
+
495
+ ### Result of three-way comparison <a id="cmp.result">[[cmp.result]]</a>
496
+
497
+ The behavior of a program that adds specializations for the
498
+ `compare_three_way_result` template defined in this subclause is
499
+ undefined.
500
+
501
+ For the `compare_three_way_result` type trait applied to the types `T`
502
+ and `U`, let `t` and `u` denote lvalues of types
503
+ `const remove_reference_t<T>` and `const remove_reference_t<U>`,
504
+ respectively. If the expression `t <=> u` is well-formed when treated as
505
+ an unevaluated operand [[expr.context]], the member *typedef-name*
506
+ `type` denotes the type `decltype(t <=> u)`. Otherwise, there is no
507
+ member `type`.
508
+
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
547
+ to greater:
548
+ - together, all negative NaN values;
549
+ - negative infinity;
550
+ - each normal negative value;
551
+ - each subnormal negative value;
552
+ - together, both zero values;
553
+ - each subnormal positive value;
554
+ - each normal positive value;
555
+ - positive infinity;
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
+