From Jason Turner

[atomics.ref.generic]

Diff to HTML by rtfpessoa

Files changed (1) hide show
  1. tmp/tmps_rve45d/{from.md → to.md} +405 -142
tmp/tmps_rve45d/{from.md → to.md} RENAMED
@@ -7,38 +7,40 @@ namespace std {
7
  template<class T> struct atomic_ref {
8
  private:
9
  T* ptr; // exposition only
10
 
11
  public:
12
- using value_type = T;
13
  static constexpr size_t required_alignment = implementation-defined // required alignment for atomic_ref type's operations;
14
 
15
  static constexpr bool is_always_lock_free = implementation-defined // whether a given atomic_ref type's operations are always lock free;
16
  bool is_lock_free() const noexcept;
17
 
18
- explicit atomic_ref(T&);
19
- atomic_ref(const atomic_ref&) noexcept;
20
  atomic_ref& operator=(const atomic_ref&) = delete;
21
 
22
- void store(T, memory_order = memory_order::seq_cst) const noexcept;
23
- T operator=(T) const noexcept;
24
- T load(memory_order = memory_order::seq_cst) const noexcept;
25
- operator T() const noexcept;
26
 
27
- T exchange(T, memory_order = memory_order::seq_cst) const noexcept;
28
- bool compare_exchange_weak(T&, T,
 
29
  memory_order, memory_order) const noexcept;
30
- bool compare_exchange_strong(T&, T,
31
  memory_order, memory_order) const noexcept;
32
- bool compare_exchange_weak(T&, T,
33
  memory_order = memory_order::seq_cst) const noexcept;
34
- bool compare_exchange_strong(T&, T,
35
  memory_order = memory_order::seq_cst) const noexcept;
36
 
37
- void wait(T, memory_order = memory_order::seq_cst) const noexcept;
38
- void notify_one() const noexcept;
39
- void notify_all() const noexcept;
 
40
  };
41
  }
42
  ```
43
 
44
  An `atomic_ref` object applies atomic operations [[atomics.general]] to
@@ -63,10 +65,13 @@ through any other `atomic_ref` referencing the same object.
63
  [*Note 1*: Atomic operations or the `atomic_ref` constructor can
64
  acquire a shared resource, such as a lock associated with the referenced
65
  object, to enable atomic operations to be applied to the referenced
66
  object. — *end note*]
67
 
 
 
 
68
  #### Operations <a id="atomics.ref.ops">[[atomics.ref.ops]]</a>
69
 
70
  ``` cpp
71
  static constexpr size_t required_alignment;
72
  ```
@@ -95,94 +100,103 @@ bool is_lock_free() const noexcept;
95
 
96
  *Returns:* `true` if operations on all objects of the type
97
  `atomic_ref<T>` are lock-free, `false` otherwise.
98
 
99
  ``` cpp
100
- atomic_ref(T& obj);
101
  ```
102
 
103
  *Preconditions:* The referenced object is aligned to
104
  `required_alignment`.
105
 
106
  *Ensures:* `*this` references `obj`.
107
 
108
  *Throws:* Nothing.
109
 
110
  ``` cpp
111
- atomic_ref(const atomic_ref& ref) noexcept;
112
  ```
113
 
114
  *Ensures:* `*this` references the object referenced by `ref`.
115
 
116
  ``` cpp
117
- void store(T desired, memory_order order = memory_order::seq_cst) const noexcept;
 
118
  ```
119
 
120
- *Preconditions:* The `order` argument is neither
121
- `memory_order::consume`, `memory_order::acquire`, nor
122
- `memory_order::acq_rel`.
 
123
 
124
  *Effects:* Atomically replaces the value referenced by `*ptr` with the
125
  value of `desired`. Memory is affected according to the value of
126
  `order`.
127
 
128
  ``` cpp
129
- T operator=(T desired) const noexcept;
130
  ```
131
 
 
 
132
  *Effects:* Equivalent to:
133
 
134
  ``` cpp
135
  store(desired);
136
  return desired;
137
  ```
138
 
139
  ``` cpp
140
- T load(memory_order order = memory_order::seq_cst) const noexcept;
141
  ```
142
 
143
- *Preconditions:* The `order` argument is neither `memory_order::release`
144
- nor `memory_order::acq_rel`.
145
 
146
  *Effects:* Memory is affected according to the value of `order`.
147
 
148
  *Returns:* Atomically returns the value referenced by `*ptr`.
149
 
150
  ``` cpp
151
- operator T() const noexcept;
152
  ```
153
 
154
  *Effects:* Equivalent to: `return load();`
155
 
156
  ``` cpp
157
- T exchange(T desired, memory_order order = memory_order::seq_cst) const noexcept;
 
158
  ```
159
 
 
 
160
  *Effects:* Atomically replaces the value referenced by `*ptr` with
161
  `desired`. Memory is affected according to the value of `order`. This
162
  operation is an atomic read-modify-write
163
  operation [[intro.multithread]].
164
 
165
  *Returns:* Atomically returns the value referenced by `*ptr` immediately
166
  before the effects.
167
 
168
  ``` cpp
169
- bool compare_exchange_weak(T& expected, T desired,
170
  memory_order success, memory_order failure) const noexcept;
171
 
172
- bool compare_exchange_strong(T& expected, T desired,
173
  memory_order success, memory_order failure) const noexcept;
174
 
175
- bool compare_exchange_weak(T& expected, T desired,
176
  memory_order order = memory_order::seq_cst) const noexcept;
177
 
178
- bool compare_exchange_strong(T& expected, T desired,
179
  memory_order order = memory_order::seq_cst) const noexcept;
180
  ```
181
 
182
- *Preconditions:* The `failure` argument is neither
183
- `memory_order::release` nor `memory_order::acq_rel`.
 
 
184
 
185
  *Effects:* Retrieves the value in `expected`. It then atomically
186
  compares the value representation of the value referenced by `*ptr` for
187
  equality with that previously retrieved from `expected`, and if `true`,
188
  replaces the value referenced by `*ptr` with that in `desired`. If and
@@ -216,15 +230,15 @@ compare-and-exchange is in a loop, the weak version will yield better
216
  performance on some platforms. When a weak compare-and-exchange would
217
  require a loop and a strong one would not, the strong one is
218
  preferable. — *end note*]
219
 
220
  ``` cpp
221
- void wait(T old, memory_order order = memory_order::seq_cst) const noexcept;
222
  ```
223
 
224
- *Preconditions:* `order` is neither `memory_order::release` nor
225
- `memory_order::acq_rel`.
226
 
227
  *Effects:* Repeatedly performs the following steps, in order:
228
 
229
  - Evaluates `load(order)` and compares its value representation for
230
  equality against that of `old`.
@@ -234,102 +248,131 @@ void wait(T old, memory_order order = memory_order::seq_cst) const noexcept;
234
 
235
  *Remarks:* This function is an atomic waiting operation [[atomics.wait]]
236
  on atomic object `*ptr`.
237
 
238
  ``` cpp
239
- void notify_one() const noexcept;
240
  ```
241
 
 
 
242
  *Effects:* Unblocks the execution of at least one atomic waiting
243
  operation on `*ptr` that is eligible to be unblocked [[atomics.wait]] by
244
  this call, if any such atomic waiting operations exist.
245
 
246
  *Remarks:* This function is an atomic notifying
247
  operation [[atomics.wait]] on atomic object `*ptr`.
248
 
249
  ``` cpp
250
- void notify_all() const noexcept;
251
  ```
252
 
 
 
253
  *Effects:* Unblocks the execution of all atomic waiting operations on
254
  `*ptr` that are eligible to be unblocked [[atomics.wait]] by this call.
255
 
256
  *Remarks:* This function is an atomic notifying
257
  operation [[atomics.wait]] on atomic object `*ptr`.
258
 
 
 
 
 
 
 
259
  #### Specializations for integral types <a id="atomics.ref.int">[[atomics.ref.int]]</a>
260
 
261
- There are specializations of the `atomic_ref` class template for the
262
- integral types `char`, `signed char`, `unsigned char`, `short`,
263
- `unsigned short`, `int`, `unsigned int`, `long`, `unsigned long`,
264
- `long long`, `unsigned long long`, `char8_t`, `char16_t`, `char32_t`,
265
- `wchar_t`, and any other types needed by the typedefs in the header
266
- `<cstdint>`. For each such type `integral-type`, the specialization
267
- `atomic_ref<integral-type>` provides additional atomic operations
268
- appropriate to integral types.
269
 
270
  [*Note 1*: The specialization `atomic_ref<bool>` uses the primary
271
  template [[atomics.ref.generic]]. — *end note*]
272
 
 
 
 
273
  ``` cpp
274
  namespace std {
275
  template<> struct atomic_ref<integral-type> {
276
  private:
277
  integral-type* ptr; // exposition only
278
 
279
  public:
280
- using value_type = integral-type;
281
  using difference_type = value_type;
282
  static constexpr size_t required_alignment = implementation-defined // required alignment for atomic_ref type's operations;
283
 
284
  static constexpr bool is_always_lock_free = implementation-defined // whether a given atomic_ref type's operations are always lock free;
285
  bool is_lock_free() const noexcept;
286
 
287
- explicit atomic_ref(integral-type&);
288
- atomic_ref(const atomic_ref&) noexcept;
289
  atomic_ref& operator=(const atomic_ref&) = delete;
290
 
291
- void store(integral-type, memory_order = memory_order::seq_cst) const noexcept;
292
- integral-type operator=(integral-type) const noexcept;
293
- integral-type load(memory_order = memory_order::seq_cst) const noexcept;
294
- operator integral-type() const noexcept;
295
 
296
- integral-type exchange(integral-type,
297
  memory_order = memory_order::seq_cst) const noexcept;
298
- bool compare_exchange_weak(integral-type&, integral-type,
299
  memory_order, memory_order) const noexcept;
300
- bool compare_exchange_strong(integral-type&, integral-type,
301
  memory_order, memory_order) const noexcept;
302
- bool compare_exchange_weak(integral-type&, integral-type,
303
  memory_order = memory_order::seq_cst) const noexcept;
304
- bool compare_exchange_strong(integral-type&, integral-type,
305
  memory_order = memory_order::seq_cst) const noexcept;
306
 
307
- integral-type fetch_add(integral-type,
308
  memory_order = memory_order::seq_cst) const noexcept;
309
- integral-type fetch_sub(integral-type,
310
  memory_order = memory_order::seq_cst) const noexcept;
311
- integral-type fetch_and(integral-type,
312
  memory_order = memory_order::seq_cst) const noexcept;
313
- integral-type fetch_or(integral-type,
314
  memory_order = memory_order::seq_cst) const noexcept;
315
- integral-type fetch_xor(integral-type,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
316
  memory_order = memory_order::seq_cst) const noexcept;
317
 
318
- integral-type operator++(int) const noexcept;
319
- integral-type operator--(int) const noexcept;
320
- integral-type operator++() const noexcept;
321
- integral-type operator--() const noexcept;
322
- integral-type operator+=(integral-type) const noexcept;
323
- integral-type operator-=(integral-type) const noexcept;
324
- integral-type operator&=(integral-type) const noexcept;
325
- integral-type operator|=(integral-type) const noexcept;
326
- integral-type operator^=(integral-type) const noexcept;
327
 
328
- void wait(integral-type, memory_order = memory_order::seq_cst) const noexcept;
329
- void notify_one() const noexcept;
330
- void notify_all() const noexcept;
 
331
  };
332
  }
333
  ```
334
 
335
  Descriptions are provided below only for members that differ from the
@@ -338,107 +381,177 @@ primary template.
338
  The following operations perform arithmetic computations. The
339
  correspondence among key, operator, and computation is specified in
340
  [[atomic.types.int.comp]].
341
 
342
  ``` cpp
343
- integral-type fetch_key(integral-type operand,
344
  memory_order order = memory_order::seq_cst) const noexcept;
345
  ```
346
 
 
 
347
  *Effects:* Atomically replaces the value referenced by `*ptr` with the
348
  result of the computation applied to the value referenced by `*ptr` and
349
  the given operand. Memory is affected according to the value of `order`.
350
  These operations are atomic read-modify-write
351
  operations [[intro.races]].
352
 
353
  *Returns:* Atomically, the value referenced by `*ptr` immediately before
354
  the effects.
355
 
356
- *Remarks:* For signed integer types, the result is as if the object
357
- value and parameters were converted to their corresponding unsigned
358
- types, the computation performed on those types, and the result
359
- converted back to the signed type.
360
 
361
  [*Note 1*: There are no undefined results arising from the
362
  computation. — *end note*]
363
 
 
 
 
 
 
364
  ``` cpp
365
- integral-type operator op=(integral-type operand) const noexcept;
 
366
  ```
367
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
368
  *Effects:* Equivalent to:
369
  `return fetch_`*`key`*`(operand) `*`op`*` operand;`
370
 
371
  #### Specializations for floating-point types <a id="atomics.ref.float">[[atomics.ref.float]]</a>
372
 
373
  There are specializations of the `atomic_ref` class template for all
374
- cv-unqualified floating-point types. For each such type
375
- `floating-point-type`, the specialization `atomic_ref<floating-point>`
376
- provides additional atomic operations appropriate to floating-point
377
- types.
 
 
378
 
379
  ``` cpp
380
  namespace std {
381
  template<> struct atomic_ref<floating-point-type> {
382
  private:
383
  floating-point-type* ptr; // exposition only
384
 
385
  public:
386
- using value_type = floating-point-type;
387
  using difference_type = value_type;
388
  static constexpr size_t required_alignment = implementation-defined // required alignment for atomic_ref type's operations;
389
 
390
  static constexpr bool is_always_lock_free = implementation-defined // whether a given atomic_ref type's operations are always lock free;
391
  bool is_lock_free() const noexcept;
392
 
393
- explicit atomic_ref(floating-point-type&);
394
- atomic_ref(const atomic_ref&) noexcept;
395
  atomic_ref& operator=(const atomic_ref&) = delete;
396
 
397
- void store(floating-point-type, memory_order = memory_order::seq_cst) const noexcept;
398
- floating-point-type operator=(floating-point-type) const noexcept;
399
- floating-point-type load(memory_order = memory_order::seq_cst) const noexcept;
400
- operator floating-point-type() const noexcept;
 
401
 
402
- floating-point-type exchange(floating-point-type,
403
  memory_order = memory_order::seq_cst) const noexcept;
404
- bool compare_exchange_weak(floating-point-type&, floating-point-type,
405
  memory_order, memory_order) const noexcept;
406
- bool compare_exchange_strong(floating-point-type&, floating-point-type,
407
  memory_order, memory_order) const noexcept;
408
- bool compare_exchange_weak(floating-point-type&, floating-point-type,
 
 
 
 
 
 
 
 
 
 
409
  memory_order = memory_order::seq_cst) const noexcept;
410
- bool compare_exchange_strong(floating-point-type&, floating-point-type,
 
 
 
 
 
 
 
 
411
  memory_order = memory_order::seq_cst) const noexcept;
412
 
413
- floating-point-type fetch_add(floating-point-type,
 
 
 
 
414
  memory_order = memory_order::seq_cst) const noexcept;
415
- floating-point-type fetch_sub(floating-point-type,
 
 
 
 
416
  memory_order = memory_order::seq_cst) const noexcept;
417
 
418
- floating-point-type operator+=(floating-point-type) const noexcept;
419
- floating-point-type operator-=(floating-point-type) const noexcept;
420
 
421
- void wait(floating-point-type, memory_order = memory_order::seq_cst) const noexcept;
422
- void notify_one() const noexcept;
423
- void notify_all() const noexcept;
 
 
424
  };
425
  }
426
  ```
427
 
428
  Descriptions are provided below only for members that differ from the
429
  primary template.
430
 
431
  The following operations perform arithmetic computations. The
432
  correspondence among key, operator, and computation is specified in
433
- [[atomic.types.int.comp]].
 
 
434
 
435
  ``` cpp
436
- floating-point-type fetch_key(floating-point-type operand,
437
  memory_order order = memory_order::seq_cst) const noexcept;
438
  ```
439
 
 
 
440
  *Effects:* Atomically replaces the value referenced by `*ptr` with the
441
  result of the computation applied to the value referenced by `*ptr` and
442
  the given operand. Memory is affected according to the value of `order`.
443
  These operations are atomic read-modify-write
444
  operations [[intro.races]].
@@ -448,71 +561,167 @@ the effects.
448
 
449
  *Remarks:* If the result is not a representable value for its
450
  type [[expr.pre]], the result is unspecified, but the operations
451
  otherwise have no undefined behavior. Atomic arithmetic operations on
452
  *`floating-point-type`* should conform to the
453
- `std::numeric_limits<`*`floating-point-type`*`>` traits associated with
454
- the floating-point type [[limits.syn]]. The floating-point
455
  environment [[cfenv]] for atomic arithmetic operations on
456
  *`floating-point-type`* may be different than the calling thread’s
457
  floating-point environment.
458
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
459
  ``` cpp
460
- floating-point-type operator op=(floating-point-type operand) const noexcept;
 
461
  ```
462
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
463
  *Effects:* Equivalent to:
464
  `return fetch_`*`key`*`(operand) `*`op`*` operand;`
465
 
466
- #### Partial specialization for pointers <a id="atomics.ref.pointer">[[atomics.ref.pointer]]</a>
 
 
 
 
 
 
 
 
467
 
468
  ``` cpp
469
  namespace std {
470
- template<class T> struct atomic_ref<T*> {
471
  private:
472
- T** ptr; // exposition only
473
 
474
  public:
475
- using value_type = T*;
476
  using difference_type = ptrdiff_t;
477
  static constexpr size_t required_alignment = implementation-defined // required alignment for atomic_ref type's operations;
478
 
479
  static constexpr bool is_always_lock_free = implementation-defined // whether a given atomic_ref type's operations are always lock free;
480
  bool is_lock_free() const noexcept;
481
 
482
- explicit atomic_ref(T*&);
483
- atomic_ref(const atomic_ref&) noexcept;
484
  atomic_ref& operator=(const atomic_ref&) = delete;
485
 
486
- void store(T*, memory_order = memory_order::seq_cst) const noexcept;
487
- T* operator=(T*) const noexcept;
488
- T* load(memory_order = memory_order::seq_cst) const noexcept;
489
- operator T*() const noexcept;
490
 
491
- T* exchange(T*, memory_order = memory_order::seq_cst) const noexcept;
492
- bool compare_exchange_weak(T*&, T*,
 
493
  memory_order, memory_order) const noexcept;
494
- bool compare_exchange_strong(T*&, T*,
495
  memory_order, memory_order) const noexcept;
496
- bool compare_exchange_weak(T*&, T*,
 
 
 
 
 
 
 
497
  memory_order = memory_order::seq_cst) const noexcept;
498
- bool compare_exchange_strong(T*&, T*,
 
 
499
  memory_order = memory_order::seq_cst) const noexcept;
500
 
501
- T* fetch_add(difference_type, memory_order = memory_order::seq_cst) const noexcept;
502
- T* fetch_sub(difference_type, memory_order = memory_order::seq_cst) const noexcept;
 
 
 
 
 
 
503
 
504
- T* operator++(int) const noexcept;
505
- T* operator--(int) const noexcept;
506
- T* operator++() const noexcept;
507
- T* operator--() const noexcept;
508
- T* operator+=(difference_type) const noexcept;
509
- T* operator-=(difference_type) const noexcept;
510
 
511
- void wait(T*, memory_order = memory_order::seq_cst) const noexcept;
512
- void notify_one() const noexcept;
513
- void notify_all() const noexcept;
 
514
  };
515
  }
516
  ```
517
 
518
  Descriptions are provided below only for members that differ from the
@@ -521,14 +730,18 @@ primary template.
521
  The following operations perform arithmetic computations. The
522
  correspondence among key, operator, and computation is specified in
523
  [[atomic.types.pointer.comp]].
524
 
525
  ``` cpp
526
- T* fetch_key(difference_type operand, memory_order order = memory_order::seq_cst) const noexcept;
 
527
  ```
528
 
529
- *Mandates:* `T` is a complete object type.
 
 
 
530
 
531
  *Effects:* Atomically replaces the value referenced by `*ptr` with the
532
  result of the computation applied to the value referenced by `*ptr` and
533
  the given operand. Memory is affected according to the value of `order`.
534
  These operations are atomic read-modify-write
@@ -538,38 +751,88 @@ operations [[intro.races]].
538
  the effects.
539
 
540
  *Remarks:* The result may be an undefined address, but the operations
541
  otherwise have no undefined behavior.
542
 
 
 
 
 
 
 
 
 
 
543
  ``` cpp
544
- T* operator op=(difference_type operand) const noexcept;
 
545
  ```
546
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
547
  *Effects:* Equivalent to:
548
  `return fetch_`*`key`*`(operand) `*`op`*` operand;`
549
 
550
  #### Member operators common to integers and pointers to objects <a id="atomics.ref.memop">[[atomics.ref.memop]]</a>
551
 
 
 
 
 
552
  ``` cpp
553
- value_type operator++(int) const noexcept;
554
  ```
555
 
 
 
556
  *Effects:* Equivalent to: `return fetch_add(1);`
557
 
558
  ``` cpp
559
- value_type operator--(int) const noexcept;
560
  ```
561
 
 
 
562
  *Effects:* Equivalent to: `return fetch_sub(1);`
563
 
564
  ``` cpp
565
- value_type operator++() const noexcept;
566
  ```
567
 
 
 
568
  *Effects:* Equivalent to: `return fetch_add(1) + 1;`
569
 
570
  ``` cpp
571
- value_type operator--() const noexcept;
572
  ```
573
 
 
 
574
  *Effects:* Equivalent to: `return fetch_sub(1) - 1;`
575
 
 
7
  template<class T> struct atomic_ref {
8
  private:
9
  T* ptr; // exposition only
10
 
11
  public:
12
+ using value_type = remove_cv_t<T>;
13
  static constexpr size_t required_alignment = implementation-defined // required alignment for atomic_ref type's operations;
14
 
15
  static constexpr bool is_always_lock_free = implementation-defined // whether a given atomic_ref type's operations are always lock free;
16
  bool is_lock_free() const noexcept;
17
 
18
+ constexpr explicit atomic_ref(T&);
19
+ constexpr atomic_ref(const atomic_ref&) noexcept;
20
  atomic_ref& operator=(const atomic_ref&) = delete;
21
 
22
+ constexpr void store(value_type, memory_order = memory_order::seq_cst) const noexcept;
23
+ constexpr value_type operator=(value_type) const noexcept;
24
+ constexpr value_type load(memory_order = memory_order::seq_cst) const noexcept;
25
+ constexpr operator value_type() const noexcept;
26
 
27
+ constexpr value_type exchange(value_type,
28
+ memory_order = memory_order::seq_cst) const noexcept;
29
+ constexpr bool compare_exchange_weak(value_type&, value_type,
30
  memory_order, memory_order) const noexcept;
31
+ constexpr bool compare_exchange_strong(value_type&, value_type,
32
  memory_order, memory_order) const noexcept;
33
+ constexpr bool compare_exchange_weak(value_type&, value_type,
34
  memory_order = memory_order::seq_cst) const noexcept;
35
+ constexpr bool compare_exchange_strong(value_type&, value_type,
36
  memory_order = memory_order::seq_cst) const noexcept;
37
 
38
+ constexpr void wait(value_type, memory_order = memory_order::seq_cst) const noexcept;
39
+ constexpr void notify_one() const noexcept;
40
+ constexpr void notify_all() const noexcept;
41
+ constexpr T* address() const noexcept;
42
  };
43
  }
44
  ```
45
 
46
  An `atomic_ref` object applies atomic operations [[atomics.general]] to
 
65
  [*Note 1*: Atomic operations or the `atomic_ref` constructor can
66
  acquire a shared resource, such as a lock associated with the referenced
67
  object, to enable atomic operations to be applied to the referenced
68
  object. — *end note*]
69
 
70
+ The program is ill-formed if `is_always_lock_free` is `false` and
71
+ `is_volatile_v<T>` is `true`.
72
+
73
  #### Operations <a id="atomics.ref.ops">[[atomics.ref.ops]]</a>
74
 
75
  ``` cpp
76
  static constexpr size_t required_alignment;
77
  ```
 
100
 
101
  *Returns:* `true` if operations on all objects of the type
102
  `atomic_ref<T>` are lock-free, `false` otherwise.
103
 
104
  ``` cpp
105
+ constexpr atomic_ref(T& obj);
106
  ```
107
 
108
  *Preconditions:* The referenced object is aligned to
109
  `required_alignment`.
110
 
111
  *Ensures:* `*this` references `obj`.
112
 
113
  *Throws:* Nothing.
114
 
115
  ``` cpp
116
+ constexpr atomic_ref(const atomic_ref& ref) noexcept;
117
  ```
118
 
119
  *Ensures:* `*this` references the object referenced by `ref`.
120
 
121
  ``` cpp
122
+ constexpr void store(value_type desired,
123
+ memory_order order = memory_order::seq_cst) const noexcept;
124
  ```
125
 
126
+ *Constraints:* `is_const_v<T>` is `false`.
127
+
128
+ *Preconditions:* `order` is `memory_order::relaxed`,
129
+ `memory_order::release`, or `memory_order::seq_cst`.
130
 
131
  *Effects:* Atomically replaces the value referenced by `*ptr` with the
132
  value of `desired`. Memory is affected according to the value of
133
  `order`.
134
 
135
  ``` cpp
136
+ constexpr value_type operator=(value_type desired) const noexcept;
137
  ```
138
 
139
+ *Constraints:* `is_const_v<T>` is `false`.
140
+
141
  *Effects:* Equivalent to:
142
 
143
  ``` cpp
144
  store(desired);
145
  return desired;
146
  ```
147
 
148
  ``` cpp
149
+ constexpr value_type load(memory_order order = memory_order::seq_cst) const noexcept;
150
  ```
151
 
152
+ *Preconditions:* `order` is `memory_order::relaxed`,
153
+ `memory_order::acquire`, or `memory_order::seq_cst`.
154
 
155
  *Effects:* Memory is affected according to the value of `order`.
156
 
157
  *Returns:* Atomically returns the value referenced by `*ptr`.
158
 
159
  ``` cpp
160
+ constexpr operator value_type() const noexcept;
161
  ```
162
 
163
  *Effects:* Equivalent to: `return load();`
164
 
165
  ``` cpp
166
+ constexpr value_type exchange(value_type desired,
167
+ memory_order order = memory_order::seq_cst) const noexcept;
168
  ```
169
 
170
+ *Constraints:* `is_const_v<T>` is `false`.
171
+
172
  *Effects:* Atomically replaces the value referenced by `*ptr` with
173
  `desired`. Memory is affected according to the value of `order`. This
174
  operation is an atomic read-modify-write
175
  operation [[intro.multithread]].
176
 
177
  *Returns:* Atomically returns the value referenced by `*ptr` immediately
178
  before the effects.
179
 
180
  ``` cpp
181
+ constexpr bool compare_exchange_weak(value_type& expected, value_type desired,
182
  memory_order success, memory_order failure) const noexcept;
183
 
184
+ constexpr bool compare_exchange_strong(value_type& expected, value_type desired,
185
  memory_order success, memory_order failure) const noexcept;
186
 
187
+ constexpr bool compare_exchange_weak(value_type& expected, value_type desired,
188
  memory_order order = memory_order::seq_cst) const noexcept;
189
 
190
+ constexpr bool compare_exchange_strong(value_type& expected, value_type desired,
191
  memory_order order = memory_order::seq_cst) const noexcept;
192
  ```
193
 
194
+ *Constraints:* `is_const_v<T>` is `false`.
195
+
196
+ *Preconditions:* `failure` is `memory_order::relaxed`,
197
+ `memory_order::acquire`, or `memory_order::seq_cst`.
198
 
199
  *Effects:* Retrieves the value in `expected`. It then atomically
200
  compares the value representation of the value referenced by `*ptr` for
201
  equality with that previously retrieved from `expected`, and if `true`,
202
  replaces the value referenced by `*ptr` with that in `desired`. If and
 
230
  performance on some platforms. When a weak compare-and-exchange would
231
  require a loop and a strong one would not, the strong one is
232
  preferable. — *end note*]
233
 
234
  ``` cpp
235
+ constexpr void wait(value_type old, memory_order order = memory_order::seq_cst) const noexcept;
236
  ```
237
 
238
+ *Preconditions:* `order` is `memory_order::relaxed`,
239
+ `memory_order::acquire`, or `memory_order::seq_cst`.
240
 
241
  *Effects:* Repeatedly performs the following steps, in order:
242
 
243
  - Evaluates `load(order)` and compares its value representation for
244
  equality against that of `old`.
 
248
 
249
  *Remarks:* This function is an atomic waiting operation [[atomics.wait]]
250
  on atomic object `*ptr`.
251
 
252
  ``` cpp
253
+ constexpr void notify_one() const noexcept;
254
  ```
255
 
256
+ *Constraints:* `is_const_v<T>` is `false`.
257
+
258
  *Effects:* Unblocks the execution of at least one atomic waiting
259
  operation on `*ptr` that is eligible to be unblocked [[atomics.wait]] by
260
  this call, if any such atomic waiting operations exist.
261
 
262
  *Remarks:* This function is an atomic notifying
263
  operation [[atomics.wait]] on atomic object `*ptr`.
264
 
265
  ``` cpp
266
+ constexpr void notify_all() const noexcept;
267
  ```
268
 
269
+ *Constraints:* `is_const_v<T>` is `false`.
270
+
271
  *Effects:* Unblocks the execution of all atomic waiting operations on
272
  `*ptr` that are eligible to be unblocked [[atomics.wait]] by this call.
273
 
274
  *Remarks:* This function is an atomic notifying
275
  operation [[atomics.wait]] on atomic object `*ptr`.
276
 
277
+ ``` cpp
278
+ constexpr T* address() const noexcept;
279
+ ```
280
+
281
+ *Returns:* `ptr`.
282
+
283
  #### Specializations for integral types <a id="atomics.ref.int">[[atomics.ref.int]]</a>
284
 
285
+ There are specializations of the `atomic_ref` class template for all
286
+ integral types except cv `bool`. For each such type `integral-type`, the
287
+ specialization `atomic_ref<integral-type>` provides additional atomic
288
+ operations appropriate to integral types.
 
 
 
 
289
 
290
  [*Note 1*: The specialization `atomic_ref<bool>` uses the primary
291
  template [[atomics.ref.generic]]. — *end note*]
292
 
293
+ The program is ill-formed if `is_always_lock_free` is `false` and
294
+ `is_volatile_v<integral-type>` is `true`.
295
+
296
  ``` cpp
297
  namespace std {
298
  template<> struct atomic_ref<integral-type> {
299
  private:
300
  integral-type* ptr; // exposition only
301
 
302
  public:
303
+ using value_type = remove_cv_t<integral-type>;
304
  using difference_type = value_type;
305
  static constexpr size_t required_alignment = implementation-defined // required alignment for atomic_ref type's operations;
306
 
307
  static constexpr bool is_always_lock_free = implementation-defined // whether a given atomic_ref type's operations are always lock free;
308
  bool is_lock_free() const noexcept;
309
 
310
+ constexpr explicit atomic_ref(integral-type&);
311
+ constexpr atomic_ref(const atomic_ref&) noexcept;
312
  atomic_ref& operator=(const atomic_ref&) = delete;
313
 
314
+ constexpr void store(value_type, memory_order = memory_order::seq_cst) const noexcept;
315
+ constexpr value_type operator=(value_type) const noexcept;
316
+ constexpr value_type load(memory_order = memory_order::seq_cst) const noexcept;
317
+ constexpr operator value_type() const noexcept;
318
 
319
+ constexpr value_type exchange(value_type,
320
  memory_order = memory_order::seq_cst) const noexcept;
321
+ constexpr bool compare_exchange_weak(value_type&, value_type,
322
  memory_order, memory_order) const noexcept;
323
+ constexpr bool compare_exchange_strong(value_type&, value_type,
324
  memory_order, memory_order) const noexcept;
325
+ constexpr bool compare_exchange_weak(value_type&, value_type,
326
  memory_order = memory_order::seq_cst) const noexcept;
327
+ constexpr bool compare_exchange_strong(value_type&, value_type,
328
  memory_order = memory_order::seq_cst) const noexcept;
329
 
330
+ constexpr value_type fetch_add(value_type,
331
  memory_order = memory_order::seq_cst) const noexcept;
332
+ constexpr value_type fetch_sub(value_type,
333
  memory_order = memory_order::seq_cst) const noexcept;
334
+ constexpr value_type fetch_and(value_type,
335
  memory_order = memory_order::seq_cst) const noexcept;
336
+ constexpr value_type fetch_or(value_type,
337
  memory_order = memory_order::seq_cst) const noexcept;
338
+ constexpr value_type fetch_xor(value_type,
339
+ memory_order = memory_order::seq_cst) const noexcept;
340
+ constexpr value_type fetch_max(value_type,
341
+ memory_order = memory_order::seq_cst) const noexcept;
342
+ constexpr value_type fetch_min(value_type,
343
+ memory_order = memory_order::seq_cst) const noexcept;
344
+
345
+ constexpr void store_add(value_type,
346
+ memory_order = memory_order::seq_cst) const noexcept;
347
+ constexpr void store_sub(value_type,
348
+ memory_order = memory_order::seq_cst) const noexcept;
349
+ constexpr void store_and(value_type,
350
+ memory_order = memory_order::seq_cst) const noexcept;
351
+ constexpr void store_or(value_type,
352
+ memory_order = memory_order::seq_cst) const noexcept;
353
+ constexpr void store_xor(value_type,
354
+ memory_order = memory_order::seq_cst) const noexcept;
355
+ constexpr void store_max(value_type,
356
+ memory_order = memory_order::seq_cst) const noexcept;
357
+ constexpr void store_min(value_type,
358
  memory_order = memory_order::seq_cst) const noexcept;
359
 
360
+ constexpr value_type operator++(int) const noexcept;
361
+ constexpr value_type operator--(int) const noexcept;
362
+ constexpr value_type operator++() const noexcept;
363
+ constexpr value_type operator--() const noexcept;
364
+ constexpr value_type operator+=(value_type) const noexcept;
365
+ constexpr value_type operator-=(value_type) const noexcept;
366
+ constexpr value_type operator&=(value_type) const noexcept;
367
+ constexpr value_type operator|=(value_type) const noexcept;
368
+ constexpr value_type operator^=(value_type) const noexcept;
369
 
370
+ constexpr void wait(value_type, memory_order = memory_order::seq_cst) const noexcept;
371
+ constexpr void notify_one() const noexcept;
372
+ constexpr void notify_all() const noexcept;
373
+ constexpr integral-type* address() const noexcept;
374
  };
375
  }
376
  ```
377
 
378
  Descriptions are provided below only for members that differ from the
 
381
  The following operations perform arithmetic computations. The
382
  correspondence among key, operator, and computation is specified in
383
  [[atomic.types.int.comp]].
384
 
385
  ``` cpp
386
+ constexpr value_type fetch_key(value_type operand,
387
  memory_order order = memory_order::seq_cst) const noexcept;
388
  ```
389
 
390
+ *Constraints:* `is_const_v<`*`integral-type`*`>` is `false`.
391
+
392
  *Effects:* Atomically replaces the value referenced by `*ptr` with the
393
  result of the computation applied to the value referenced by `*ptr` and
394
  the given operand. Memory is affected according to the value of `order`.
395
  These operations are atomic read-modify-write
396
  operations [[intro.races]].
397
 
398
  *Returns:* Atomically, the value referenced by `*ptr` immediately before
399
  the effects.
400
 
401
+ *Remarks:* Except for `fetch_max` and `fetch_min`, for signed integer
402
+ types the result is as if the object value and parameters were converted
403
+ to their corresponding unsigned types, the computation performed on
404
+ those types, and the result converted back to the signed type.
405
 
406
  [*Note 1*: There are no undefined results arising from the
407
  computation. — *end note*]
408
 
409
+ For `fetch_max` and `fetch_min`, the maximum and minimum computation is
410
+ performed as if by `max` and `min` algorithms [[alg.min.max]],
411
+ respectively, with the object value and the first parameter as the
412
+ arguments.
413
+
414
  ``` cpp
415
+ constexpr void store_key(value_type operand,
416
+ memory_order order = memory_order::seq_cst) const noexcept;
417
  ```
418
 
419
+ *Preconditions:* `order` is `memory_order::relaxed`,
420
+ `memory_order::release`, or `memory_order::seq_cst`.
421
+
422
+ *Effects:* Atomically replaces the value referenced by `*ptr` with the
423
+ result of the computation applied to the value referenced by `*ptr` and
424
+ the given `operand`. Memory is affected according to the value of
425
+ `order`. These operations are atomic modify-write
426
+ operations [[atomics.order]].
427
+
428
+ *Remarks:* Except for `store_max` and `store_min`, for signed integer
429
+ types, the result is as if `*ptr` and parameters were converted to their
430
+ corresponding unsigned types, the computation performed on those types,
431
+ and the result converted back to the signed type.
432
+
433
+ [*Note 2*: There are no undefined results arising from the
434
+ computation. — *end note*]
435
+
436
+ For `store_max` and `store_min`, the maximum and minimum computation is
437
+ performed as if by `max` and `min` algorithms [[alg.min.max]],
438
+ respectively, with `*ptr` and the first parameter as the arguments.
439
+
440
+ ``` cpp
441
+ constexpr value_type operator op=(value_type operand) const noexcept;
442
+ ```
443
+
444
+ *Constraints:* `is_const_v<`*`integral-type`*`>` is `false`.
445
+
446
  *Effects:* Equivalent to:
447
  `return fetch_`*`key`*`(operand) `*`op`*` operand;`
448
 
449
  #### Specializations for floating-point types <a id="atomics.ref.float">[[atomics.ref.float]]</a>
450
 
451
  There are specializations of the `atomic_ref` class template for all
452
+ floating-point types. For each such type `floating-point-type`, the
453
+ specialization `atomic_ref<floating-point-type>` provides additional
454
+ atomic operations appropriate to floating-point types.
455
+
456
+ The program is ill-formed if `is_always_lock_free` is `false` and
457
+ `is_volatile_v<floating-point-type>` is `true`.
458
 
459
  ``` cpp
460
  namespace std {
461
  template<> struct atomic_ref<floating-point-type> {
462
  private:
463
  floating-point-type* ptr; // exposition only
464
 
465
  public:
466
+ using value_type = remove_cv_t<floating-point-type>;
467
  using difference_type = value_type;
468
  static constexpr size_t required_alignment = implementation-defined // required alignment for atomic_ref type's operations;
469
 
470
  static constexpr bool is_always_lock_free = implementation-defined // whether a given atomic_ref type's operations are always lock free;
471
  bool is_lock_free() const noexcept;
472
 
473
+ constexpr explicit atomic_ref(floating-point-type&);
474
+ constexpr atomic_ref(const atomic_ref&) noexcept;
475
  atomic_ref& operator=(const atomic_ref&) = delete;
476
 
477
+ constexpr void store(value_type,
478
+ memory_order = memory_order::seq_cst) const noexcept;
479
+ constexpr value_type operator=(value_type) const noexcept;
480
+ constexpr value_type load(memory_order = memory_order::seq_cst) const noexcept;
481
+ constexpr operator value_type() const noexcept;
482
 
483
+ constexpr value_type exchange(value_type,
484
  memory_order = memory_order::seq_cst) const noexcept;
485
+ constexpr bool compare_exchange_weak(value_type&, value_type,
486
  memory_order, memory_order) const noexcept;
487
+ constexpr bool compare_exchange_strong(value_type&, value_type,
488
  memory_order, memory_order) const noexcept;
489
+ constexpr bool compare_exchange_weak(value_type&, value_type,
490
+ memory_order = memory_order::seq_cst) const noexcept;
491
+ constexpr bool compare_exchange_strong(value_type&, value_type,
492
+ memory_order = memory_order::seq_cst) const noexcept;
493
+
494
+ constexpr value_type fetch_add(value_type,
495
+ memory_order = memory_order::seq_cst) const noexcept;
496
+ constexpr value_type fetch_sub(value_type,
497
+ memory_order = memory_order::seq_cst) const noexcept;
498
+
499
+ constexpr value_type fetch_max(value_type,
500
  memory_order = memory_order::seq_cst) const noexcept;
501
+ constexpr value_type fetch_min(value_type,
502
+ memory_order = memory_order::seq_cst) const noexcept;
503
+ constexpr value_type fetch_fmaximum(value_type,
504
+ memory_order = memory_order::seq_cst) const noexcept;
505
+ constexpr value_type fetch_fminimum(value_type,
506
+ memory_order = memory_order::seq_cst) const noexcept;
507
+ constexpr value_type fetch_fmaximum_num(value_type,
508
+ memory_order = memory_order::seq_cst) const noexcept;
509
+ constexpr value_type fetch_fminimum_num(value_type,
510
  memory_order = memory_order::seq_cst) const noexcept;
511
 
512
+ constexpr void store_add(value_type, memory_order = memory_order::seq_cst) const noexcept;
513
+ constexpr void store_sub(value_type, memory_order = memory_order::seq_cst) const noexcept;
514
+ constexpr void store_max(value_type, memory_order = memory_order::seq_cst) const noexcept;
515
+ constexpr void store_min(value_type, memory_order = memory_order::seq_cst) const noexcept;
516
+ constexpr void store_fmaximum(value_type,
517
  memory_order = memory_order::seq_cst) const noexcept;
518
+ constexpr void store_fminimum(value_type,
519
+ memory_order = memory_order::seq_cst) const noexcept;
520
+ constexpr void store_fmaximum_num(value_type,
521
+ memory_order = memory_order::seq_cst) const noexcept;
522
+ constexpr void store_fminimum_num(value_type,
523
  memory_order = memory_order::seq_cst) const noexcept;
524
 
525
+ constexpr value_type operator+=(value_type) const noexcept;
526
+ constexpr value_type operator-=(value_type) const noexcept;
527
 
528
+ constexpr void wait(value_type,
529
+ memory_order = memory_order::seq_cst) const noexcept;
530
+ constexpr void notify_one() const noexcept;
531
+ constexpr void notify_all() const noexcept;
532
+ constexpr floating-point-type* address() const noexcept;
533
  };
534
  }
535
  ```
536
 
537
  Descriptions are provided below only for members that differ from the
538
  primary template.
539
 
540
  The following operations perform arithmetic computations. The
541
  correspondence among key, operator, and computation is specified in
542
+ [[atomic.types.int.comp]], except for the keys `max`, `min`, `fmaximum`,
543
+ `fminimum`, `fmaximum_num`, and `fminimum_num`, which are specified
544
+ below.
545
 
546
  ``` cpp
547
+ constexpr value_type fetch_key(value_type operand,
548
  memory_order order = memory_order::seq_cst) const noexcept;
549
  ```
550
 
551
+ *Constraints:* `is_const_v<`*`floating-point-type`*`>` is `false`.
552
+
553
  *Effects:* Atomically replaces the value referenced by `*ptr` with the
554
  result of the computation applied to the value referenced by `*ptr` and
555
  the given operand. Memory is affected according to the value of `order`.
556
  These operations are atomic read-modify-write
557
  operations [[intro.races]].
 
561
 
562
  *Remarks:* If the result is not a representable value for its
563
  type [[expr.pre]], the result is unspecified, but the operations
564
  otherwise have no undefined behavior. Atomic arithmetic operations on
565
  *`floating-point-type`* should conform to the
566
+ `std::numeric_limits<value_type>` traits associated with the
567
+ floating-point type [[limits.syn]]. The floating-point
568
  environment [[cfenv]] for atomic arithmetic operations on
569
  *`floating-point-type`* may be different than the calling thread’s
570
  floating-point environment.
571
 
572
+ - For `fetch_fmaximum` and `fetch_fminimum`, the maximum and minimum
573
+ computation is performed as if by `fmaximum` and `fminimum`,
574
+ respectively, with `*ptr` and the first parameter as the arguments.
575
+ - For `fetch_fmaximum_num` and `fetch_fminimum_num`, the maximum and
576
+ minimum computation is performed as if by `fmaximum_num` and
577
+ `fminimum_num`, respectively, with `*ptr` and the first parameter as
578
+ the arguments.
579
+ - For `fetch_max` and `fetch_min`, the maximum and minimum computation
580
+ is performed as if by `fmaximum_num` and `fminimum_num`, respectively,
581
+ with `*ptr` and the first parameter as the arguments, except that:
582
+ - If both arguments are NaN, an unspecified NaN value is stored at
583
+ `*ptr`.
584
+ - If exactly one argument is a NaN, either the other argument or an
585
+ unspecified NaN value is stored at `*ptr`; it is unspecified which.
586
+ - If the arguments are differently signed zeros, which of these values
587
+ is stored at `*ptr` is unspecified.
588
+
589
+ *Recommended practice:* The implementation of `fetch_max` and
590
+ `fetch_min` should treat negative zero as smaller than positive zero.
591
+
592
  ``` cpp
593
+ constexpr void store_key(value_type operand,
594
+ memory_order order = memory_order::seq_cst) const noexcept;
595
  ```
596
 
597
+ *Preconditions:* `order` is `memory_order::relaxed`,
598
+ `memory_order::release`, or `memory_order::seq_cst`.
599
+
600
+ *Effects:* Atomically replaces the value referenced by `*ptr` with the
601
+ result of the computation applied to the value referenced by `*ptr` and
602
+ the given `operand`. Memory is affected according to the value of
603
+ `order`. These operations are atomic modify-write
604
+ operations [[atomics.order]].
605
+
606
+ *Remarks:* If the result is not a representable value for its
607
+ type [[expr.pre]], the result is unspecified, but the operations
608
+ otherwise have no undefined behavior. Atomic arithmetic operations on
609
+ *`floating-point-type`* should conform to the
610
+ `numeric_limits<`*`floating-point-type`*`>` traits associated with the
611
+ floating-point type [[limits.syn]]. The floating-point
612
+ environment [[cfenv]] for atomic arithmetic operations on
613
+ *`floating-point-type`* may be different than the calling thread’s
614
+ floating-point environment. The arithmetic rules of floating-point
615
+ atomic modify-write operations may be different from operations on
616
+ floating-point types or atomic floating-point types.
617
+
618
+ [*Note 1*: Tree reductions are permitted for atomic modify-write
619
+ operations. — *end note*]
620
+
621
+ - For `store_fmaximum` and `store_fminimum`, the maximum and minimum
622
+ computation is performed as if by `fmaximum` and `fminimum`,
623
+ respectively, with `*ptr` and the first parameter as the arguments.
624
+ - For `store_fmaximum_num` and `store_fminimum_num`, the maximum and
625
+ minimum computation is performed as if by `fmaximum_num `and
626
+ `fminimum_num`, respectively, with `*ptr` and the first parameter as
627
+ the arguments.
628
+ - For `store_max` and `store_min`, the maximum and minimum computation
629
+ is performed as if by `fmaximum_num` and `fminimum_num`, respectively,
630
+ with `*ptr` and the first parameter as the arguments, except that:
631
+ - If both arguments are NaN, an unspecified NaN value is stored at
632
+ `*ptr`.
633
+ - If exactly one argument is a NaN, either the other argument or an
634
+ unspecified NaN value is stored at `*ptr`, it is unspecified which.
635
+ - If the arguments are differently signed zeros, which of these values
636
+ is stored at `*ptr` is unspecified.
637
+
638
+ *Recommended practice:* The implementation of `store_max` and
639
+ `store_min` should treat negative zero as smaller than positive zero.
640
+
641
+ ``` cpp
642
+ constexpr value_type operator op=(value_type operand) const noexcept;
643
+ ```
644
+
645
+ *Constraints:* `is_const_v<`*`floating-point-type`*`>` is `false`.
646
+
647
  *Effects:* Equivalent to:
648
  `return fetch_`*`key`*`(operand) `*`op`*` operand;`
649
 
650
+ #### Specialization for pointers <a id="atomics.ref.pointer">[[atomics.ref.pointer]]</a>
651
+
652
+ There are specializations of the `atomic_ref` class template for all
653
+ pointer-to-object types. For each such type `pointer-type`, the
654
+ specialization `atomic_ref<pointer-type>` provides additional atomic
655
+ operations appropriate to pointer types.
656
+
657
+ The program is ill-formed if `is_always_lock_free` is `false` and
658
+ `is_volatile_v<pointer-type>` is `true`.
659
 
660
  ``` cpp
661
  namespace std {
662
+ template<> struct atomic_ref<pointer-type> {
663
  private:
664
+ pointer-type* ptr; // exposition only
665
 
666
  public:
667
+ using value_type = remove_cv_t<pointer-type>;
668
  using difference_type = ptrdiff_t;
669
  static constexpr size_t required_alignment = implementation-defined // required alignment for atomic_ref type's operations;
670
 
671
  static constexpr bool is_always_lock_free = implementation-defined // whether a given atomic_ref type's operations are always lock free;
672
  bool is_lock_free() const noexcept;
673
 
674
+ constexpr explicit atomic_ref(pointer-type&);
675
+ constexpr atomic_ref(const atomic_ref&) noexcept;
676
  atomic_ref& operator=(const atomic_ref&) = delete;
677
 
678
+ constexpr void store(value_type, memory_order = memory_order::seq_cst) const noexcept;
679
+ constexpr value_type operator=(value_type) const noexcept;
680
+ constexpr value_type load(memory_order = memory_order::seq_cst) const noexcept;
681
+ constexpr operator value_type() const noexcept;
682
 
683
+ constexpr value_type exchange(value_type,
684
+ memory_order = memory_order::seq_cst) const noexcept;
685
+ constexpr bool compare_exchange_weak(value_type&, value_type,
686
  memory_order, memory_order) const noexcept;
687
+ constexpr bool compare_exchange_strong(value_type&, value_type,
688
  memory_order, memory_order) const noexcept;
689
+ constexpr bool compare_exchange_weak(value_type&, value_type,
690
+ memory_order = memory_order::seq_cst) const noexcept;
691
+ constexpr bool compare_exchange_strong(value_type&, value_type,
692
+ memory_order = memory_order::seq_cst) const noexcept;
693
+
694
+ constexpr value_type fetch_add(difference_type,
695
+ memory_order = memory_order::seq_cst) const noexcept;
696
+ constexpr value_type fetch_sub(difference_type,
697
  memory_order = memory_order::seq_cst) const noexcept;
698
+ constexpr value_type fetch_max(value_type,
699
+ memory_order = memory_order::seq_cst) const noexcept;
700
+ constexpr value_type fetch_min(value_type,
701
  memory_order = memory_order::seq_cst) const noexcept;
702
 
703
+ constexpr void store_add(difference_type,
704
+ memory_order = memory_order::seq_cst) const noexcept;
705
+ constexpr void store_sub(difference_type,
706
+ memory_order = memory_order::seq_cst) const noexcept;
707
+ constexpr void store_max(value_type,
708
+ memory_order = memory_order::seq_cst) const noexcept;
709
+ constexpr void store_min(value_type,
710
+ memory_order = memory_order::seq_cst) const noexcept;
711
 
712
+ constexpr value_type operator++(int) const noexcept;
713
+ constexpr value_type operator--(int) const noexcept;
714
+ constexpr value_type operator++() const noexcept;
715
+ constexpr value_type operator--() const noexcept;
716
+ constexpr value_type operator+=(difference_type) const noexcept;
717
+ constexpr value_type operator-=(difference_type) const noexcept;
718
 
719
+ constexpr void wait(value_type, memory_order = memory_order::seq_cst) const noexcept;
720
+ constexpr void notify_one() const noexcept;
721
+ constexpr void notify_all() const noexcept;
722
+ constexpr pointer-type* address() const noexcept;
723
  };
724
  }
725
  ```
726
 
727
  Descriptions are provided below only for members that differ from the
 
730
  The following operations perform arithmetic computations. The
731
  correspondence among key, operator, and computation is specified in
732
  [[atomic.types.pointer.comp]].
733
 
734
  ``` cpp
735
+ constexpr value_type fetch_key(\seeabovenc operand,
736
+ memory_order order = memory_order::seq_cst) const noexcept;
737
  ```
738
 
739
+ *Constraints:* `is_const_v<`*`pointer-type`*`>` is `false`.
740
+
741
+ *Mandates:* `remove_pointer_t<`*`pointer-type`*`>` is a complete object
742
+ type.
743
 
744
  *Effects:* Atomically replaces the value referenced by `*ptr` with the
745
  result of the computation applied to the value referenced by `*ptr` and
746
  the given operand. Memory is affected according to the value of `order`.
747
  These operations are atomic read-modify-write
 
751
  the effects.
752
 
753
  *Remarks:* The result may be an undefined address, but the operations
754
  otherwise have no undefined behavior.
755
 
756
+ For `fetch_max` and `fetch_min`, the maximum and minimum computation is
757
+ performed as if by `max` and `min` algorithms [[alg.min.max]],
758
+ respectively, with the object value and the first parameter as the
759
+ arguments.
760
+
761
+ [*Note 1*: If the pointers point to different complete objects (or
762
+ subobjects thereof), the `<` operator does not establish a strict weak
763
+ ordering ([[cpp17.lessthancomparable]], [[expr.rel]]). — *end note*]
764
+
765
  ``` cpp
766
+ constexpr void store_key(\seeabovenc operand,
767
+ memory_order order = memory_order::seq_cst) const noexcept;
768
  ```
769
 
770
+ *Mandates:* `remove_pointer_t<`*`pointer-type`*`>` is a complete object
771
+ type.
772
+
773
+ *Preconditions:* `order` is `memory_order::relaxed`,
774
+ `memory_order::release`, or `memory_order::seq_cst`.
775
+
776
+ *Effects:* Atomically replaces the value referenced by `*ptr` with the
777
+ result of the computation applied to the value referenced by `*ptr` and
778
+ the given `operand`. Memory is affected according to the value of
779
+ `order`. These operations are atomic modify-write
780
+ operations [[atomics.order]].
781
+
782
+ *Remarks:* The result may be an undefined address, but the operations
783
+ otherwise have no undefined behavior. For `store_max` and `store_min`,
784
+ the `maximum` and `minimum` computation is performed as if by `max` and
785
+ `min` algorithms [[alg.min.max]], respectively, with `*ptr` and the
786
+ first parameter as the arguments.
787
+
788
+ [*Note 2*: If the pointers point to different complete objects (or
789
+ subobjects thereof), the `<` operator does not establish a strict weak
790
+ ordering ([[cpp17.lessthancomparable]], [[expr.rel]]). — *end note*]
791
+
792
+ ``` cpp
793
+ constexpr value_type operator op=(difference_type operand) const noexcept;
794
+ ```
795
+
796
+ *Constraints:* `is_const_v<`*`pointer-type`*`>` is `false`.
797
+
798
  *Effects:* Equivalent to:
799
  `return fetch_`*`key`*`(operand) `*`op`*` operand;`
800
 
801
  #### Member operators common to integers and pointers to objects <a id="atomics.ref.memop">[[atomics.ref.memop]]</a>
802
 
803
+ Let `referred-type` be `pointer-type` for the specializations in
804
+ [[atomics.ref.pointer]] and be `integral-type` for the specializations
805
+ in [[atomics.ref.int]].
806
+
807
  ``` cpp
808
+ constexpr value_type operator++(int) const noexcept;
809
  ```
810
 
811
+ *Constraints:* `is_const_v<`*`referred-type`*`>` is `false`.
812
+
813
  *Effects:* Equivalent to: `return fetch_add(1);`
814
 
815
  ``` cpp
816
+ constexpr value_type operator--(int) const noexcept;
817
  ```
818
 
819
+ *Constraints:* `is_const_v<`*`referred-type`*`>` is `false`.
820
+
821
  *Effects:* Equivalent to: `return fetch_sub(1);`
822
 
823
  ``` cpp
824
+ constexpr value_type operator++() const noexcept;
825
  ```
826
 
827
+ *Constraints:* `is_const_v<`*`referred-type`*`>` is `false`.
828
+
829
  *Effects:* Equivalent to: `return fetch_add(1) + 1;`
830
 
831
  ``` cpp
832
+ constexpr value_type operator--() const noexcept;
833
  ```
834
 
835
+ *Constraints:* `is_const_v<`*`referred-type`*`>` is `false`.
836
+
837
  *Effects:* Equivalent to: `return fetch_sub(1) - 1;`
838