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