From Jason Turner

[concept.swappable]

Diff to HTML by rtfpessoa

Files changed (1) hide show
  1. tmp/tmpo81dgbeq/{from.md → to.md} +134 -0
tmp/tmpo81dgbeq/{from.md → to.md} RENAMED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ### Concept <a id="concept.swappable">[[concept.swappable]]</a>
2
+
3
+ Let `t1` and `t2` be equality-preserving expressions that denote
4
+ distinct equal objects of type `T`, and let `u1` and `u2` similarly
5
+ denote distinct equal objects of type `U`.
6
+
7
+ [*Note 1*: `t1` and `u1` can denote distinct objects, or the same
8
+ object. — *end note*]
9
+
10
+ An operation *exchanges the values* denoted by `t1` and `u1` if and only
11
+ if the operation modifies neither `t2` nor `u2` and:
12
+
13
+ - If `T` and `U` are the same type, the result of the operation is that
14
+ `t1` equals `u2` and `u1` equals `t2`.
15
+ - If `T` and `U` are different types and
16
+ `common_reference_with<decltype((t1)), decltype((u1))>` is modeled,
17
+ the result of the operation is that `C(t1)` equals `C(u2)` and `C(u1)`
18
+ equals `C(t2)` where `C` is
19
+ `common_reference_t<decltype((t1)), decltype((u1))>`.
20
+
21
+ The name `ranges::swap` denotes a customization point object
22
+ [[customization.point.object]]. The expression `ranges::swap(E1, E2)`
23
+ for subexpressions `E1` and `E2` is expression-equivalent to an
24
+ expression `S` determined as follows:
25
+
26
+ - `S` is `(void)swap(E1, E2)`[^1] if `E1` or `E2` has class or
27
+ enumeration type [[basic.compound]] and that expression is valid, with
28
+ overload resolution performed in a context that includes the
29
+ declaration
30
+ ``` cpp
31
+ template<class T>
32
+ void swap(T&, T&) = delete;
33
+ ```
34
+
35
+ and does not include a declaration of `ranges::swap`. If the function
36
+ selected by overload resolution does not exchange the values denoted
37
+ by `E1` and `E2`, the program is ill-formed, no diagnostic required.
38
+ - Otherwise, if `E1` and `E2` are lvalues of array types
39
+ [[basic.compound]] with equal extent and `ranges::swap(*E1, *E2)` is a
40
+ valid expression, `S` is `(void)ranges::swap_ranges(E1, E2)`, except
41
+ that `noexcept(S)` is equal to `noexcept({}ranges::swap(*E1, *E2))`.
42
+ - Otherwise, if `E1` and `E2` are lvalues of the same type `T` that
43
+ models `move_constructible<T>` and `assignable_from<T&, T>`, `S` is an
44
+ expression that exchanges the denoted values. `S` is a constant
45
+ expression if
46
+ - `T` is a literal type [[basic.types]],
47
+ - both `E1 = std::move(E2)` and `E2 = std::move(E1)` are constant
48
+ subexpressions [[defns.const.subexpr]], and
49
+ - the full-expressions of the initializers in the declarations
50
+ ``` cpp
51
+ T t1(std::move(E1));
52
+ T t2(std::move(E2));
53
+ ```
54
+
55
+ are constant subexpressions.
56
+
57
+ `noexcept(S)` is equal to
58
+ `is_nothrow_move_constructible_v<T> && is_nothrow_move_assignable_v<T>`.
59
+ - Otherwise, `ranges::swap(E1, E2)` is ill-formed. \[*Note 2*: This case
60
+ can result in substitution failure when `ranges::swap(E1, E2)` appears
61
+ in the immediate context of a template instantiation. — *end note*]
62
+
63
+ [*Note 3*: Whenever `ranges::swap(E1, E2)` is a valid expression, it
64
+ exchanges the values denoted by `E1` and `E2` and has type
65
+ `void`. — *end note*]
66
+
67
+ ``` cpp
68
+ template<class T>
69
+ concept swappable = requires(T& a, T& b) { ranges::swap(a, b); };
70
+ ```
71
+
72
+ ``` cpp
73
+ template<class T, class U>
74
+ concept swappable_with =
75
+ common_reference_with<T, U> &&
76
+ requires(T&& t, U&& u) {
77
+ ranges::swap(std::forward<T>(t), std::forward<T>(t));
78
+ ranges::swap(std::forward<U>(u), std::forward<U>(u));
79
+ ranges::swap(std::forward<T>(t), std::forward<U>(u));
80
+ ranges::swap(std::forward<U>(u), std::forward<T>(t));
81
+ };
82
+ ```
83
+
84
+ [*Note 4*: The semantics of the `swappable` and `swappable_with`
85
+ concepts are fully defined by the `ranges::swap` customization
86
+ point. — *end note*]
87
+
88
+ [*Example 1*:
89
+
90
+ User code can ensure that the evaluation of `swap` calls is performed in
91
+ an appropriate context under the various conditions as follows:
92
+
93
+ ``` cpp
94
+ #include <cassert>
95
+ #include <concepts>
96
+ #include <utility>
97
+
98
+ namespace ranges = std::ranges;
99
+
100
+ template<class T, std::swappable_with<T> U>
101
+ void value_swap(T&& t, U&& u) {
102
+ ranges::swap(std::forward<T>(t), std::forward<U>(u));
103
+ }
104
+
105
+ template<std::swappable T>
106
+ void lv_swap(T& t1, T& t2) {
107
+ ranges::swap(t1, t2);
108
+ }
109
+
110
+ namespace N {
111
+ struct A { int m; };
112
+ struct Proxy {
113
+ A* a;
114
+ Proxy(A& a) : a{&a} {}
115
+ friend void swap(Proxy x, Proxy y) {
116
+ ranges::swap(*x.a, *y.a);
117
+ }
118
+ };
119
+ Proxy proxy(A& a) { return Proxy{ a }; }
120
+ }
121
+
122
+ int main() {
123
+ int i = 1, j = 2;
124
+ lv_swap(i, j);
125
+ assert(i == 2 && j == 1);
126
+
127
+ N::A a1 = { 5 }, a2 = { -5 };
128
+ value_swap(a1, proxy(a2));
129
+ assert(a1.m == -5 && a2.m == 5);
130
+ }
131
+ ```
132
+
133
+ — *end example*]
134
+