From Jason Turner

[const.wrap.class]

Diff to HTML by rtfpessoa

Files changed (1) hide show
  1. tmp/tmpnrmhlo3b/{from.md → to.md} +258 -0
tmp/tmpnrmhlo3b/{from.md → to.md} RENAMED
@@ -0,0 +1,258 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ### Class template `constant_wrapper` <a id="const.wrap.class">[[const.wrap.class]]</a>
2
+
3
+ ``` cpp
4
+ namespace std {
5
+ template<class T>
6
+ struct cw-fixed-value { // exposition only
7
+ using type = T; // exposition only
8
+ constexpr cw-fixed-value(type v) noexcept : data(v) {}
9
+ T data; // exposition only
10
+ };
11
+
12
+ template<class T, size_t Extent>
13
+ struct cw-fixed-value<T[Extent]> { // exposition only
14
+ using type = T[Extent]; // exposition only
15
+ constexpr cw-fixed-value(T (&arr)[Extent]) noexcept;
16
+ T data[Extent]; // exposition only
17
+ };
18
+
19
+ template<class T, size_t Extent>
20
+ cw-fixed-value(T (&)[Extent]) -> cw-fixed-value<T[Extent]>; // exposition only
21
+
22
+ struct cw-operators { // exposition only
23
+ // unary operators
24
+ template<constexpr-param T>
25
+ friend constexpr auto operator+(T) noexcept -> constant_wrapper<(+T::value)>
26
+ { return {}; }
27
+ template<constexpr-param T>
28
+ friend constexpr auto operator-(T) noexcept -> constant_wrapper<(-T::value)>
29
+ { return {}; }
30
+ template<constexpr-param T>
31
+ friend constexpr auto operator~(T) noexcept -> constant_wrapper<(~T::value)>
32
+ { return {}; }
33
+ template<constexpr-param T>
34
+ friend constexpr auto operator!(T) noexcept -> constant_wrapper<(!T::value)>
35
+ { return {}; }
36
+ template<constexpr-param T>
37
+ friend constexpr auto operator&(T) noexcept -> constant_wrapper<(&T::value)>
38
+ { return {}; }
39
+ template<constexpr-param T>
40
+ friend constexpr auto operator*(T) noexcept -> constant_wrapper<(*T::value)>
41
+ { return {}; }
42
+
43
+ // binary operators
44
+ template<constexpr-param L, constexpr-param R>
45
+ friend constexpr auto operator+(L, R) noexcept -> constant_wrapper<(L::value + R::value)>
46
+ { return {}; }
47
+ template<constexpr-param L, constexpr-param R>
48
+ friend constexpr auto operator-(L, R) noexcept -> constant_wrapper<(L::value - R::value)>
49
+ { return {}; }
50
+ template<constexpr-param L, constexpr-param R>
51
+ friend constexpr auto operator*(L, R) noexcept -> constant_wrapper<(L::value * R::value)>
52
+ { return {}; }
53
+ template<constexpr-param L, constexpr-param R>
54
+ friend constexpr auto operator/(L, R) noexcept -> constant_wrapper<(L::value / R::value)>
55
+ { return {}; }
56
+ template<constexpr-param L, constexpr-param R>
57
+ friend constexpr auto operator%(L, R) noexcept -> constant_wrapper<(L::value % R::value)>
58
+ { return {}; }
59
+
60
+ template<constexpr-param L, constexpr-param R>
61
+ friend constexpr auto operator<<(L, R) noexcept -> constant_wrapper<(L::value << R::value)>
62
+ { return {}; }
63
+ template<constexpr-param L, constexpr-param R>
64
+ friend constexpr auto operator>>(L, R) noexcept -> constant_wrapper<(L::value >> R::value)>
65
+ { return {}; }
66
+ template<constexpr-param L, constexpr-param R>
67
+ friend constexpr auto operator&(L, R) noexcept -> constant_wrapper<(L::value & R::value)>
68
+ { return {}; }
69
+ template<constexpr-param L, constexpr-param R>
70
+ friend constexpr auto operator|(L, R) noexcept -> constant_wrapper<(L::value | R::value)>
71
+ { return {}; }
72
+ template<constexpr-param L, constexpr-param R>
73
+ friend constexpr auto operator^(L, R) noexcept -> constant_wrapper<(L::value ^ R::value)>
74
+ { return {}; }
75
+
76
+ template<constexpr-param L, constexpr-param R>
77
+ requires (!is_constructible_v<bool, decltype(L::value)> ||
78
+ !is_constructible_v<bool, decltype(R::value)>)
79
+ friend constexpr auto operator&&(L, R) noexcept
80
+ -> constant_wrapper<(L::value && R::value)>
81
+ { return {}; }
82
+ template<constexpr-param L, constexpr-param R>
83
+ requires (!is_constructible_v<bool, decltype(L::value)> ||
84
+ !is_constructible_v<bool, decltype(R::value)>)
85
+ friend constexpr auto operator||(L, R) noexcept
86
+ -> constant_wrapper<(L::value || R::value)>
87
+ { return {}; }
88
+
89
+ // comparisons
90
+ template<constexpr-param L, constexpr-param R>
91
+ friend constexpr auto operator<=>(L, R) noexcept
92
+ -> constant_wrapper<(L::value <=> R::value)>
93
+ { return {}; }
94
+ template<constexpr-param L, constexpr-param R>
95
+ friend constexpr auto operator<(L, R) noexcept -> constant_wrapper<(L::value < R::value)>
96
+ { return {}; }
97
+ template<constexpr-param L, constexpr-param R>
98
+ friend constexpr auto operator<=(L, R) noexcept -> constant_wrapper<(L::value <= R::value)>
99
+ { return {}; }
100
+ template<constexpr-param L, constexpr-param R>
101
+ friend constexpr auto operator==(L, R) noexcept -> constant_wrapper<(L::value == R::value)>
102
+ { return {}; }
103
+ template<constexpr-param L, constexpr-param R>
104
+ friend constexpr auto operator!=(L, R) noexcept -> constant_wrapper<(L::value != R::value)>
105
+ { return {}; }
106
+ template<constexpr-param L, constexpr-param R>
107
+ friend constexpr auto operator>(L, R) noexcept -> constant_wrapper<(L::value > R::value)>
108
+ { return {}; }
109
+ template<constexpr-param L, constexpr-param R>
110
+ friend constexpr auto operator>=(L, R) noexcept -> constant_wrapper<(L::value >= R::value)>
111
+ { return {}; }
112
+
113
+ template<constexpr-param L, constexpr-param R>
114
+ friend constexpr auto operator,(L, R) noexcept = delete;
115
+ template<constexpr-param L, constexpr-param R>
116
+ friend constexpr auto operator->*(L, R) noexcept -> constant_wrapper<L::value->*(R::value)>
117
+ { return {}; }
118
+
119
+ // call and index
120
+ template<constexpr-param T, constexpr-param... Args>
121
+ constexpr auto operator()(this T, Args...) noexcept
122
+ requires requires { constant_wrapper<T::value(Args::value...)>(); }
123
+ { return constant_wrapper<T::value(Args::value...)>{}; }
124
+ template<constexpr-param T, constexpr-param... Args>
125
+ constexpr auto operator[](this T, Args...) noexcept
126
+ -> constant_wrapper<(T::value[Args::value...])>
127
+ { return {}; }
128
+
129
+ // pseudo-mutators
130
+ template<constexpr-param T>
131
+ constexpr auto operator++(this T) noexcept
132
+ requires requires(T::value_type x) { ++x; }
133
+ { return constant_wrapper<[] { auto c = T::value; return ++c; }()>{}; }
134
+ template<constexpr-param T>
135
+ constexpr auto operator++(this T, int) noexcept
136
+ requires requires(T::value_type x) { x++; }
137
+ { return constant_wrapper<[] { auto c = T::value; return c++; }()>{}; }
138
+
139
+ template<constexpr-param T>
140
+ constexpr auto operator--(this T) noexcept
141
+ requires requires(T::value_type x) { --x; }
142
+ { return constant_wrapper<[] { auto c = T::value; return --c; }()>{}; }
143
+ template<constexpr-param T>
144
+ constexpr auto operator--(this T, int) noexcept
145
+ requires requires(T::value_type x) { x--; }
146
+ { return constant_wrapper<[] { auto c = T::value; return c--; }()>{}; }
147
+
148
+ template<constexpr-param T, constexpr-param R>
149
+ constexpr auto operator+=(this T, R) noexcept
150
+ requires requires(T::value_type x) { x += R::value; }
151
+ { return constant_wrapper<[] { auto v = T::value; return v += R::value; }()>{}; }
152
+ template<constexpr-param T, constexpr-param R>
153
+ constexpr auto operator-=(this T, R) noexcept
154
+ requires requires(T::value_type x) { x -= R::value; }
155
+ { return constant_wrapper<[] { auto v = T::value; return v -= R::value; }()>{}; }
156
+ template<constexpr-param T, constexpr-param R>
157
+ constexpr auto operator*=(this T, R) noexcept
158
+ requires requires(T::value_type x) { x *= R::value; }
159
+ { return constant_wrapper<[] { auto v = T::value; return v *= R::value; }()>{}; }
160
+ template<constexpr-param T, constexpr-param R>
161
+ constexpr auto operator/=(this T, R) noexcept
162
+ requires requires(T::value_type x) { x /= R::value; }
163
+ { return constant_wrapper<[] { auto v = T::value; return v /= R::value; }()>{}; }
164
+ template<constexpr-param T, constexpr-param R>
165
+ constexpr auto operator%=(this T, R) noexcept
166
+ requires requires(T::value_type x) { x %= R::value; }
167
+ { return constant_wrapper<[] { auto v = T::value; return v %= R::value; }()>{}; }
168
+ template<constexpr-param T, constexpr-param R>
169
+ constexpr auto operator&=(this T, R) noexcept
170
+ requires requires(T::value_type x) { x &= R::value; }
171
+ { return constant_wrapper<[] { auto v = T::value; return v &= R::value; }()>{}; }
172
+ template<constexpr-param T, constexpr-param R>
173
+ constexpr auto operator|=(this T, R) noexcept
174
+ requires requires(T::value_type x) { x |= R::value; }
175
+ { return constant_wrapper<[] { auto v = T::value; return v |= R::value; }()>{}; }
176
+ template<constexpr-param T, constexpr-param R>
177
+ constexpr auto operator^=(this T, R) noexcept
178
+ requires requires(T::value_type x) { x ^= R::value; }
179
+ { return constant_wrapper<[] { auto v = T::value; return v ^= R::value; }()>{}; }
180
+ template<constexpr-param T, constexpr-param R>
181
+ constexpr auto operator<<=(this T, R) noexcept
182
+ requires requires(T::value_type x) { x <<= R::value; }
183
+ { return constant_wrapper<[] { auto v = T::value; return v <<= R::value; }()>{}; }
184
+ template<constexpr-param T, constexpr-param R>
185
+ constexpr auto operator>>=(this T, R) noexcept
186
+ requires requires(T::value_type x) { x >>= R::value; }
187
+ { return constant_wrapper<[] { auto v = T::value; return v >>= R::value; }()>{}; }
188
+ };
189
+
190
+ template<cw-fixed-value X, class>
191
+ struct constant_wrapper : cw-operators {
192
+ static constexpr const auto & value = X.data;
193
+ using type = constant_wrapper;
194
+ using value_type = decltype(X)::type;
195
+
196
+ template<constexpr-param R>
197
+ constexpr auto operator=(R) const noexcept
198
+ requires requires(value_type x) { x = R::value; }
199
+ { return constant_wrapper<[] { auto v = value; return v = R::value; }()>{}; }
200
+
201
+ constexpr operator decltype(auto)() const noexcept { return value; }
202
+ };
203
+ }
204
+ ```
205
+
206
+ The class template `constant_wrapper` aids in metaprogramming by
207
+ ensuring that the evaluation of expressions comprised entirely of
208
+ `constant_wrapper` are core constant expressions [[expr.const]],
209
+ regardless of the context in which they appear. In particular, this
210
+ enables use of `constant_wrapper` values that are passed as arguments to
211
+ constexpr functions to be used in constant expressions.
212
+
213
+ [*Note 1*: The unnamed second template parameter to `constant_wrapper`
214
+ is present to aid argument-dependent lookup [[basic.lookup.argdep]] in
215
+ finding overloads for which `constant_wrapper`’s wrapped value is a
216
+ suitable argument, but for which the `constant_wrapper` itself is
217
+ not. — *end note*]
218
+
219
+ [*Example 1*:
220
+
221
+ ``` cpp
222
+ constexpr auto initial_phase(auto quantity_1, auto quantity_2) {
223
+ return quantity_1 + quantity_2;
224
+ }
225
+
226
+ constexpr auto middle_phase(auto tbd) {
227
+ return tbd;
228
+ }
229
+
230
+ void final_phase(auto gathered, auto available) {
231
+ if constexpr (gathered == available)
232
+ std::cout << "Profit!\n";
233
+ }
234
+
235
+ void impeccable_underground_planning() {
236
+ auto gathered_quantity = middle_phase(initial_phase(std::cw<42>, std::cw<13>));
237
+ static_assert(gathered_quantity == 55);
238
+ auto all_available = std::cw<55>;
239
+ final_phase(gathered_quantity, all_available);
240
+ }
241
+
242
+ void deeply_flawed_underground_planning() {
243
+ constexpr auto gathered_quantity = middle_phase(initial_phase(42, 13));
244
+ constexpr auto all_available = 55;
245
+ final_phase(gathered_quantity, all_available); // error: gathered == available
246
+ // is not a constant expression
247
+ }
248
+ ```
249
+
250
+ — *end example*]
251
+
252
+ ``` cpp
253
+ constexpr cw-fixed-value(T (&arr)[Extent]) noexcept;
254
+ ```
255
+
256
+ *Effects:* Initialize elements of *data* with corresponding elements of
257
+ `arr`.
258
+