xref: /llvm-project/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.assign/move.pass.cpp (revision a0839b14df6de99fe29bee7cdfff182d50de665d)
1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 // <tuple>
10 
11 // template <class... Types> class tuple;
12 
13 // tuple& operator=(tuple&& u);
14 
15 // UNSUPPORTED: c++03
16 
17 #include <memory>
18 #include <tuple>
19 #include <utility>
20 #include <cassert>
21 
22 #include "test_macros.h"
23 #include "MoveOnly.h"
24 
25 struct NonAssignable {
26   NonAssignable& operator=(NonAssignable const&) = delete;
27   NonAssignable& operator=(NonAssignable&&) = delete;
28 };
29 struct CopyAssignable {
30   CopyAssignable& operator=(CopyAssignable const&) = default;
31   CopyAssignable& operator=(CopyAssignable&&) = delete;
32 };
33 static_assert(std::is_copy_assignable<CopyAssignable>::value, "");
34 struct MoveAssignable {
35   MoveAssignable& operator=(MoveAssignable const&) = delete;
36   MoveAssignable& operator=(MoveAssignable&&) = default;
37 };
38 struct NothrowMoveAssignable {
39   NothrowMoveAssignable& operator=(NothrowMoveAssignable&&) noexcept { return *this; }
40 };
41 struct PotentiallyThrowingMoveAssignable {
42   PotentiallyThrowingMoveAssignable& operator=(PotentiallyThrowingMoveAssignable&&) { return *this; }
43 };
44 
45 struct CountAssign {
46   static int copied;
47   static int moved;
48   static void reset() { copied = moved = 0; }
49   CountAssign() = default;
50   CountAssign& operator=(CountAssign const&) { ++copied; return *this; }
51   CountAssign& operator=(CountAssign&&) { ++moved; return *this; }
52 };
53 int CountAssign::copied = 0;
54 int CountAssign::moved = 0;
55 
56 int main(int, char**)
57 {
58     {
59         typedef std::tuple<> T;
60         T t0;
61         T t;
62         t = std::move(t0);
63     }
64     {
65         typedef std::tuple<MoveOnly> T;
66         T t0(MoveOnly(0));
67         T t;
68         t = std::move(t0);
69         assert(std::get<0>(t) == 0);
70     }
71     {
72         typedef std::tuple<MoveOnly, MoveOnly> T;
73         T t0(MoveOnly(0), MoveOnly(1));
74         T t;
75         t = std::move(t0);
76         assert(std::get<0>(t) == 0);
77         assert(std::get<1>(t) == 1);
78     }
79     {
80         typedef std::tuple<MoveOnly, MoveOnly, MoveOnly> T;
81         T t0(MoveOnly(0), MoveOnly(1), MoveOnly(2));
82         T t;
83         t = std::move(t0);
84         assert(std::get<0>(t) == 0);
85         assert(std::get<1>(t) == 1);
86         assert(std::get<2>(t) == 2);
87     }
88     {
89         // test reference assignment.
90         using T = std::tuple<int&, int&&>;
91         int x = 42;
92         int y = 100;
93         int x2 = -1;
94         int y2 = 500;
95         T t(x, std::move(y));
96         T t2(x2, std::move(y2));
97         t = std::move(t2);
98         assert(std::get<0>(t) == x2);
99         assert(&std::get<0>(t) == &x);
100         assert(std::get<1>(t) == y2);
101         assert(&std::get<1>(t) == &y);
102     }
103     {
104         // test that the implicitly generated move assignment operator
105         // is properly deleted
106         using T = std::tuple<std::unique_ptr<int>>;
107         static_assert(std::is_move_assignable<T>::value, "");
108         static_assert(!std::is_copy_assignable<T>::value, "");
109     }
110     {
111       using T = std::tuple<int, NonAssignable>;
112       static_assert(!std::is_move_assignable<T>::value, "");
113     }
114     {
115         using T = std::tuple<int, MoveAssignable>;
116         static_assert(std::is_move_assignable<T>::value, "");
117     }
118     {
119         // The move should decay to a copy.
120         CountAssign::reset();
121         using T = std::tuple<CountAssign, CopyAssignable>;
122         static_assert(std::is_move_assignable<T>::value, "");
123         T t1;
124         T t2;
125         t1 = std::move(t2);
126         assert(CountAssign::copied == 1);
127         assert(CountAssign::moved == 0);
128     }
129     {
130         using T = std::tuple<int, NonAssignable>;
131         static_assert(!std::is_move_assignable<T>::value, "");
132     }
133     {
134         using T = std::tuple<int, MoveAssignable>;
135         static_assert(std::is_move_assignable<T>::value, "");
136     }
137     {
138         using T = std::tuple<NothrowMoveAssignable, int>;
139         static_assert(std::is_nothrow_move_assignable<T>::value, "");
140     }
141     {
142         using T = std::tuple<PotentiallyThrowingMoveAssignable, int>;
143         static_assert(!std::is_nothrow_move_assignable<T>::value, "");
144     }
145 
146     return 0;
147 }
148