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 // template <class U1, class U2> 14 // tuple& operator=(pair<U1, U2>&& u); 15 16 // UNSUPPORTED: c++03 17 18 #include <tuple> 19 #include <utility> 20 #include <memory> 21 #include <cassert> 22 23 #include "test_macros.h" 24 25 struct B 26 { 27 int id_; 28 29 explicit B(int i = 0) : id_(i) {} 30 31 virtual ~B() {} 32 }; 33 34 struct D 35 : B 36 { 37 explicit D(int i) : B(i) {} 38 }; 39 40 struct TrackMove 41 { 42 TrackMove() : value(0), moved_from(false) { } 43 explicit TrackMove(int v) : value(v), moved_from(false) { } 44 TrackMove(TrackMove const& other) : value(other.value), moved_from(false) { } 45 TrackMove(TrackMove&& other) : value(other.value), moved_from(false) { 46 other.moved_from = true; 47 } 48 TrackMove& operator=(TrackMove const& other) { 49 value = other.value; 50 moved_from = false; 51 return *this; 52 } 53 TrackMove& operator=(TrackMove&& other) { 54 value = other.value; 55 moved_from = false; 56 other.moved_from = true; 57 return *this; 58 } 59 60 int value; 61 bool moved_from; 62 }; 63 64 struct NonAssignable 65 { 66 NonAssignable& operator=(NonAssignable const&) = delete; 67 NonAssignable& operator=(NonAssignable&&) = delete; 68 }; 69 70 struct MoveAssignable 71 { 72 MoveAssignable& operator=(MoveAssignable const&) = delete; 73 MoveAssignable& operator=(MoveAssignable&&) = default; 74 }; 75 76 struct CopyAssignable 77 { 78 CopyAssignable& operator=(CopyAssignable const&) = default; 79 CopyAssignable& operator=(CopyAssignable&&) = delete; 80 }; 81 82 struct NothrowMoveAssignable 83 { 84 NothrowMoveAssignable& operator=(NothrowMoveAssignable&&) noexcept { return *this; } 85 }; 86 87 struct PotentiallyThrowingMoveAssignable 88 { 89 PotentiallyThrowingMoveAssignable& operator=(PotentiallyThrowingMoveAssignable&&) { return *this; } 90 }; 91 92 int main(int, char**) 93 { 94 { 95 typedef std::pair<long, std::unique_ptr<D>> T0; 96 typedef std::tuple<long long, std::unique_ptr<B>> T1; 97 T0 t0(2, std::unique_ptr<D>(new D(3))); 98 T1 t1; 99 t1 = std::move(t0); 100 assert(std::get<0>(t1) == 2); 101 assert(std::get<1>(t1)->id_ == 3); 102 } 103 { 104 using T = std::tuple<int, NonAssignable>; 105 using P = std::pair<int, NonAssignable>; 106 static_assert(!std::is_assignable<T&, P&&>::value, ""); 107 } 108 { 109 using T = std::tuple<int, int, int>; 110 using P = std::pair<int, int>; 111 static_assert(!std::is_assignable<T&, P&&>::value, ""); 112 } 113 { 114 typedef std::tuple<NothrowMoveAssignable, long> Tuple; 115 typedef std::pair<NothrowMoveAssignable, int> Pair; 116 static_assert(std::is_nothrow_assignable<Tuple&, Pair&&>::value, ""); 117 static_assert(!std::is_assignable<Tuple&, Pair const&&>::value, ""); 118 } 119 { 120 typedef std::tuple<PotentiallyThrowingMoveAssignable, long> Tuple; 121 typedef std::pair<PotentiallyThrowingMoveAssignable, int> Pair; 122 static_assert(std::is_assignable<Tuple&, Pair&&>::value, ""); 123 static_assert(!std::is_nothrow_assignable<Tuple&, Pair&&>::value, ""); 124 static_assert(!std::is_assignable<Tuple&, Pair const&&>::value, ""); 125 } 126 { 127 // We assign through the reference and don't move out of the incoming ref, 128 // so this doesn't work (but would if the type were CopyAssignable). 129 { 130 using T = std::tuple<MoveAssignable&, int>; 131 using P = std::pair<MoveAssignable&, int>; 132 static_assert(!std::is_assignable<T&, P&&>::value, ""); 133 } 134 135 // ... works if it's CopyAssignable 136 { 137 using T = std::tuple<CopyAssignable&, int>; 138 using P = std::pair<CopyAssignable&, int>; 139 static_assert(std::is_assignable<T&, P&&>::value, ""); 140 } 141 142 // For rvalue-references, we can move-assign if the type is MoveAssignable 143 // or CopyAssignable (since in the worst case the move will decay into a copy). 144 { 145 using T1 = std::tuple<MoveAssignable&&, int>; 146 using P1 = std::pair<MoveAssignable&&, int>; 147 static_assert(std::is_assignable<T1&, P1&&>::value, ""); 148 149 using T2 = std::tuple<CopyAssignable&&, int>; 150 using P2 = std::pair<CopyAssignable&&, int>; 151 static_assert(std::is_assignable<T2&, P2&&>::value, ""); 152 } 153 154 // In all cases, we can't move-assign if the types are not assignable, 155 // since we assign through the reference. 156 { 157 using T1 = std::tuple<NonAssignable&, int>; 158 using P1 = std::pair<NonAssignable&, int>; 159 static_assert(!std::is_assignable<T1&, P1&&>::value, ""); 160 161 using T2 = std::tuple<NonAssignable&&, int>; 162 using P2 = std::pair<NonAssignable&&, int>; 163 static_assert(!std::is_assignable<T2&, P2&&>::value, ""); 164 } 165 } 166 { 167 // Make sure that we don't incorrectly move out of the source's reference. 168 using Dest = std::tuple<TrackMove, int>; 169 using Source = std::pair<TrackMove&, int>; 170 TrackMove track{3}; 171 Source src(track, 4); 172 assert(!track.moved_from); 173 174 Dest dst; 175 dst = std::move(src); // here we should make a copy 176 assert(!track.moved_from); 177 assert(std::get<0>(dst).value == 3); 178 } 179 { 180 // But we do move out of the source's reference if it's a rvalue ref 181 using Dest = std::tuple<TrackMove, int>; 182 using Source = std::pair<TrackMove&&, int>; 183 TrackMove track{3}; 184 Source src(std::move(track), 4); 185 assert(!track.moved_from); // we just took a reference 186 187 Dest dst; 188 dst = std::move(src); 189 assert(track.moved_from); 190 assert(std::get<0>(dst).value == 3); 191 } 192 { 193 // If the pair holds a value, then we move out of it too 194 using Dest = std::tuple<TrackMove, int>; 195 using Source = std::pair<TrackMove, int>; 196 Source src(TrackMove{3}, 4); 197 Dest dst; 198 dst = std::move(src); 199 assert(src.first.moved_from); 200 assert(std::get<0>(dst).value == 3); 201 } 202 203 return 0; 204 } 205