2 //===----------------------------------------------------------------------===//
4 // The LLVM Compiler Infrastructure
6 // This file is dual licensed under the MIT and the University of Illinois Open
7 // Source Licenses. See LICENSE.TXT for details.
9 //===----------------------------------------------------------------------===//
11 // UNSUPPORTED: c++98, c++03, c++11, c++14
15 // template <class ...Types> class variant;
17 // variant& operator=(variant&&) noexcept(see below);
21 #include <type_traits>
25 #include "test_macros.h"
26 #include "variant_test_helpers.hpp"
29 NoCopy(const NoCopy &) = delete;
30 NoCopy &operator=(const NoCopy &) = default;
34 CopyOnly(const CopyOnly &) = default;
35 CopyOnly(CopyOnly &&) = delete;
36 CopyOnly &operator=(const CopyOnly &) = default;
37 CopyOnly &operator=(CopyOnly &&) = delete;
41 MoveOnly(const MoveOnly &) = delete;
42 MoveOnly(MoveOnly &&) = default;
43 MoveOnly &operator=(const MoveOnly &) = delete;
44 MoveOnly &operator=(MoveOnly &&) = default;
48 MoveOnlyNT(const MoveOnlyNT &) = delete;
49 MoveOnlyNT(MoveOnlyNT &&) {}
50 MoveOnlyNT &operator=(const MoveOnlyNT &) = delete;
51 MoveOnlyNT &operator=(MoveOnlyNT &&) = default;
54 struct MoveOnlyOddNothrow {
55 MoveOnlyOddNothrow(MoveOnlyOddNothrow &&) noexcept(false) {}
56 MoveOnlyOddNothrow(const MoveOnlyOddNothrow &) = delete;
57 MoveOnlyOddNothrow &operator=(MoveOnlyOddNothrow &&) noexcept = default;
58 MoveOnlyOddNothrow &operator=(const MoveOnlyOddNothrow &) = delete;
61 struct MoveAssignOnly {
62 MoveAssignOnly(MoveAssignOnly &&) = delete;
63 MoveAssignOnly &operator=(MoveAssignOnly &&) = default;
67 static int move_construct;
68 static int move_assign;
69 static void reset() { move_construct = move_assign = 0; }
70 MoveAssign(int v) : value(v) {}
71 MoveAssign(MoveAssign &&o) : value(o.value) {
75 MoveAssign &operator=(MoveAssign &&o) {
84 int MoveAssign::move_construct = 0;
85 int MoveAssign::move_assign = 0;
87 void test_move_assignment_noexcept() {
89 using V = std::variant<int>;
90 static_assert(std::is_nothrow_move_assignable<V>::value, "");
93 using V = std::variant<MoveOnly>;
94 static_assert(std::is_nothrow_move_assignable<V>::value, "");
97 using V = std::variant<int, long>;
98 static_assert(std::is_nothrow_move_assignable<V>::value, "");
101 using V = std::variant<int, MoveOnly>;
102 static_assert(std::is_nothrow_move_assignable<V>::value, "");
105 using V = std::variant<MoveOnlyNT>;
106 static_assert(!std::is_nothrow_move_assignable<V>::value, "");
109 using V = std::variant<MoveOnlyOddNothrow>;
110 static_assert(!std::is_nothrow_move_assignable<V>::value, "");
114 void test_move_assignment_sfinae() {
116 using V = std::variant<int, long>;
117 static_assert(std::is_move_assignable<V>::value, "");
120 // variant only provides move assignment when both the move constructor
121 // and move assignment operator are well formed.
122 using V = std::variant<int, CopyOnly>;
123 static_assert(!std::is_move_assignable<V>::value, "");
126 using V = std::variant<int, NoCopy>;
127 static_assert(!std::is_move_assignable<V>::value, "");
130 using V = std::variant<int, MoveOnly>;
131 static_assert(std::is_move_assignable<V>::value, "");
134 using V = std::variant<int, MoveOnlyNT>;
135 static_assert(std::is_move_assignable<V>::value, "");
138 // variant only provides move assignment when the types also provide
139 // a move constructor.
140 using V = std::variant<int, MoveAssignOnly>;
141 static_assert(!std::is_move_assignable<V>::value, "");
145 void test_move_assignment_empty_empty() {
146 #ifndef TEST_HAS_NO_EXCEPTIONS
147 using MET = MakeEmptyT;
149 using V = std::variant<int, long, MET>;
150 V v1(std::in_place_index<0>);
152 V v2(std::in_place_index<0>);
154 V &vref = (v1 = std::move(v2));
155 assert(&vref == &v1);
156 assert(v1.valueless_by_exception());
157 assert(v1.index() == std::variant_npos);
162 void test_move_assignment_non_empty_empty() {
163 #ifndef TEST_HAS_NO_EXCEPTIONS
164 using MET = MakeEmptyT;
166 using V = std::variant<int, MET>;
167 V v1(std::in_place_index<0>, 42);
168 V v2(std::in_place_index<0>);
170 V &vref = (v1 = std::move(v2));
171 assert(&vref == &v1);
172 assert(v1.valueless_by_exception());
173 assert(v1.index() == std::variant_npos);
176 using V = std::variant<int, MET, std::string>;
177 V v1(std::in_place_index<2>, "hello");
178 V v2(std::in_place_index<0>);
180 V &vref = (v1 = std::move(v2));
181 assert(&vref == &v1);
182 assert(v1.valueless_by_exception());
183 assert(v1.index() == std::variant_npos);
188 void test_move_assignment_empty_non_empty() {
189 #ifndef TEST_HAS_NO_EXCEPTIONS
190 using MET = MakeEmptyT;
192 using V = std::variant<int, MET>;
193 V v1(std::in_place_index<0>);
195 V v2(std::in_place_index<0>, 42);
196 V &vref = (v1 = std::move(v2));
197 assert(&vref == &v1);
198 assert(v1.index() == 0);
199 assert(std::get<0>(v1) == 42);
202 using V = std::variant<int, MET, std::string>;
203 V v1(std::in_place_index<0>);
205 V v2(std::in_place_type<std::string>, "hello");
206 V &vref = (v1 = std::move(v2));
207 assert(&vref == &v1);
208 assert(v1.index() == 2);
209 assert(std::get<2>(v1) == "hello");
214 void test_move_assignment_same_index() {
216 using V = std::variant<int>;
219 V &vref = (v1 = std::move(v2));
220 assert(&vref == &v1);
221 assert(v1.index() == 0);
222 assert(std::get<0>(v1) == 42);
225 using V = std::variant<int, long, unsigned>;
228 V &vref = (v1 = std::move(v2));
229 assert(&vref == &v1);
230 assert(v1.index() == 1);
231 assert(std::get<1>(v1) == 42);
234 using V = std::variant<int, MoveAssign, unsigned>;
235 V v1(std::in_place_type<MoveAssign>, 43);
236 V v2(std::in_place_type<MoveAssign>, 42);
238 V &vref = (v1 = std::move(v2));
239 assert(&vref == &v1);
240 assert(v1.index() == 1);
241 assert(std::get<1>(v1).value == 42);
242 assert(MoveAssign::move_construct == 0);
243 assert(MoveAssign::move_assign == 1);
245 #ifndef TEST_HAS_NO_EXCEPTIONS
246 using MET = MakeEmptyT;
248 using V = std::variant<int, MET, std::string>;
249 V v1(std::in_place_type<MET>);
250 MET &mref = std::get<1>(v1);
251 V v2(std::in_place_type<MET>);
257 assert(v1.index() == 1);
258 assert(&std::get<1>(v1) == &mref);
263 void test_move_assignment_different_index() {
265 using V = std::variant<int, long, unsigned>;
268 V &vref = (v1 = std::move(v2));
269 assert(&vref == &v1);
270 assert(v1.index() == 1);
271 assert(std::get<1>(v1) == 42);
274 using V = std::variant<int, MoveAssign, unsigned>;
275 V v1(std::in_place_type<unsigned>, 43);
276 V v2(std::in_place_type<MoveAssign>, 42);
278 V &vref = (v1 = std::move(v2));
279 assert(&vref == &v1);
280 assert(v1.index() == 1);
281 assert(std::get<1>(v1).value == 42);
282 assert(MoveAssign::move_construct == 1);
283 assert(MoveAssign::move_assign == 0);
285 #ifndef TEST_HAS_NO_EXCEPTIONS
286 using MET = MakeEmptyT;
288 using V = std::variant<int, MET, std::string>;
289 V v1(std::in_place_type<int>);
290 V v2(std::in_place_type<MET>);
296 assert(v1.valueless_by_exception());
297 assert(v1.index() == std::variant_npos);
300 using V = std::variant<int, MET, std::string>;
301 V v1(std::in_place_type<MET>);
302 V v2(std::in_place_type<std::string>, "hello");
303 V &vref = (v1 = std::move(v2));
304 assert(&vref == &v1);
305 assert(v1.index() == 2);
306 assert(std::get<2>(v1) == "hello");
312 test_move_assignment_empty_empty();
313 test_move_assignment_non_empty_empty();
314 test_move_assignment_empty_non_empty();
315 test_move_assignment_same_index();
316 test_move_assignment_different_index();
317 test_move_assignment_sfinae();
318 test_move_assignment_noexcept();