@@ -196,6 +196,120 @@ void test_destroy_n() {
196
196
assert (g_alive == 0 );
197
197
}
198
198
199
+ struct copy_elision_dest ;
200
+
201
+ class pinned {
202
+ public:
203
+ explicit pinned (int n) : n_{n} {}
204
+
205
+ pinned (const pinned&) = delete ;
206
+ pinned& operator =(const pinned&) = delete ;
207
+
208
+ private:
209
+ friend copy_elision_dest;
210
+
211
+ int n_;
212
+ };
213
+
214
+ class pinned_ioterator {
215
+ private:
216
+ struct arrow_proxy {
217
+ pinned val_;
218
+
219
+ pinned* operator ->() {
220
+ return &val_;
221
+ }
222
+ };
223
+
224
+ public:
225
+ using value_type = pinned;
226
+ using difference_type = int ;
227
+ using reference = pinned;
228
+ using pointer = arrow_proxy;
229
+ using iterator_category = std::input_iterator_tag;
230
+
231
+ explicit pinned_ioterator (int n) : n_{n} {}
232
+
233
+ pinned operator *() const {
234
+ return pinned{n_};
235
+ }
236
+ pinned_ioterator& operator ++() {
237
+ ++n_;
238
+ return *this ;
239
+ }
240
+ pinned_ioterator operator ++(int ) {
241
+ auto old = *this ;
242
+ ++*this ;
243
+ return old;
244
+ }
245
+
246
+ arrow_proxy operator ->() const {
247
+ return arrow_proxy{pinned{n_}};
248
+ }
249
+
250
+ friend bool operator ==(pinned_ioterator i, pinned_ioterator j) {
251
+ return i.n_ == j.n_ ;
252
+ }
253
+ #if !_HAS_CXX20
254
+ friend bool operator !=(pinned_ioterator i, pinned_ioterator j) {
255
+ return !(i == j);
256
+ }
257
+ #endif // !_HAS_CXX20
258
+
259
+ private:
260
+ int n_;
261
+ };
262
+
263
+ struct copy_elision_dest {
264
+ public:
265
+ copy_elision_dest () = default ;
266
+ explicit copy_elision_dest (pinned x) : n_{x.n_ } {}
267
+
268
+ int n_;
269
+ };
270
+
271
+ // std::uninitialized_copy/_n are required to perform guaranteed copy elision since C++17.
272
+ void test_guaranteed_copy_elision_uninitialized_copy () {
273
+ constexpr int len = 42 ;
274
+
275
+ copy_elision_dest d[len];
276
+ uninitialized_copy (pinned_ioterator{0 }, pinned_ioterator{len}, d);
277
+ for (int i = 0 ; i != len; ++i) {
278
+ assert (d[i].n_ == i);
279
+ }
280
+ }
281
+
282
+ void test_guaranteed_copy_elision_uninitialized_copy_n () {
283
+ constexpr int len = 42 ;
284
+
285
+ copy_elision_dest d[len];
286
+ uninitialized_copy_n (pinned_ioterator{0 }, len, d);
287
+ for (int i = 0 ; i != len; ++i) {
288
+ assert (d[i].n_ == i);
289
+ }
290
+ }
291
+
292
+ // Also test LWG-3918 "std::uninitialized_move/_n and guaranteed copy elision".
293
+ void test_guaranteed_copy_elision_uninitialized_move () {
294
+ constexpr int len = 42 ;
295
+
296
+ copy_elision_dest d[len];
297
+ uninitialized_move (pinned_ioterator{0 }, pinned_ioterator{len}, d);
298
+ for (int i = 0 ; i != len; ++i) {
299
+ assert (d[i].n_ == i);
300
+ }
301
+ }
302
+
303
+ void test_guaranteed_copy_elision_uninitialized_move_n () {
304
+ constexpr int len = 42 ;
305
+
306
+ copy_elision_dest d[len];
307
+ uninitialized_move_n (pinned_ioterator{0 }, len, d);
308
+ for (int i = 0 ; i != len; ++i) {
309
+ assert (d[i].n_ == i);
310
+ }
311
+ }
312
+
199
313
int main () {
200
314
test_uninitialized_move ();
201
315
test_uninitialized_move_n ();
@@ -206,4 +320,9 @@ int main() {
206
320
test_destroy_at ();
207
321
test_destroy ();
208
322
test_destroy_n ();
323
+
324
+ test_guaranteed_copy_elision_uninitialized_copy ();
325
+ test_guaranteed_copy_elision_uninitialized_copy_n ();
326
+ test_guaranteed_copy_elision_uninitialized_move ();
327
+ test_guaranteed_copy_elision_uninitialized_move_n ();
209
328
}
0 commit comments