xref: /llvm-project/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.assign/move_pair.pass.cpp (revision 618862e89a022b2e8f73a62bed7c91654060dbab)
15a83710eSEric Fiselier //===----------------------------------------------------------------------===//
25a83710eSEric Fiselier //
357b08b09SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
457b08b09SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
557b08b09SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65a83710eSEric Fiselier //
75a83710eSEric Fiselier //===----------------------------------------------------------------------===//
85a83710eSEric Fiselier 
95a83710eSEric Fiselier // <tuple>
105a83710eSEric Fiselier 
115a83710eSEric Fiselier // template <class... Types> class tuple;
125a83710eSEric Fiselier 
135a83710eSEric Fiselier // template <class U1, class U2>
145a83710eSEric Fiselier //   tuple& operator=(pair<U1, U2>&& u);
155a83710eSEric Fiselier 
1631cbe0f2SLouis Dionne // UNSUPPORTED: c++03
170a52cd79SEric Fiselier 
185a83710eSEric Fiselier #include <tuple>
195a83710eSEric Fiselier #include <utility>
205a83710eSEric Fiselier #include <memory>
215a83710eSEric Fiselier #include <cassert>
225a83710eSEric Fiselier 
237fc6a556SMarshall Clow #include "test_macros.h"
247fc6a556SMarshall Clow 
255a83710eSEric Fiselier struct B
265a83710eSEric Fiselier {
275a83710eSEric Fiselier     int id_;
285a83710eSEric Fiselier 
BB295a83710eSEric Fiselier     explicit B(int i = 0) : id_(i) {}
305a83710eSEric Fiselier 
~BB315a83710eSEric Fiselier     virtual ~B() {}
325a83710eSEric Fiselier };
335a83710eSEric Fiselier 
345a83710eSEric Fiselier struct D
355a83710eSEric Fiselier     : B
365a83710eSEric Fiselier {
DD375a83710eSEric Fiselier     explicit D(int i) : B(i) {}
385a83710eSEric Fiselier };
395a83710eSEric Fiselier 
40*618862e8SLouis Dionne struct TrackMove
41*618862e8SLouis Dionne {
TrackMoveTrackMove42*618862e8SLouis Dionne     TrackMove() : value(0), moved_from(false) { }
TrackMoveTrackMove43*618862e8SLouis Dionne     explicit TrackMove(int v) : value(v), moved_from(false) { }
TrackMoveTrackMove44*618862e8SLouis Dionne     TrackMove(TrackMove const& other) : value(other.value), moved_from(false) { }
TrackMoveTrackMove45*618862e8SLouis Dionne     TrackMove(TrackMove&& other) : value(other.value), moved_from(false) {
46*618862e8SLouis Dionne         other.moved_from = true;
47*618862e8SLouis Dionne     }
operator =TrackMove48*618862e8SLouis Dionne     TrackMove& operator=(TrackMove const& other) {
49*618862e8SLouis Dionne         value = other.value;
50*618862e8SLouis Dionne         moved_from = false;
51*618862e8SLouis Dionne         return *this;
52*618862e8SLouis Dionne     }
operator =TrackMove53*618862e8SLouis Dionne     TrackMove& operator=(TrackMove&& other) {
54*618862e8SLouis Dionne         value = other.value;
55*618862e8SLouis Dionne         moved_from = false;
56*618862e8SLouis Dionne         other.moved_from = true;
57*618862e8SLouis Dionne         return *this;
58*618862e8SLouis Dionne     }
59*618862e8SLouis Dionne 
60*618862e8SLouis Dionne     int value;
61*618862e8SLouis Dionne     bool moved_from;
62*618862e8SLouis Dionne };
63*618862e8SLouis Dionne 
64a0839b14SLouis Dionne struct NonAssignable
65a0839b14SLouis Dionne {
66a0839b14SLouis Dionne   NonAssignable& operator=(NonAssignable const&) = delete;
67a0839b14SLouis Dionne   NonAssignable& operator=(NonAssignable&&) = delete;
68a0839b14SLouis Dionne };
69a0839b14SLouis Dionne 
70*618862e8SLouis Dionne struct MoveAssignable
71*618862e8SLouis Dionne {
72*618862e8SLouis Dionne   MoveAssignable& operator=(MoveAssignable const&) = delete;
73*618862e8SLouis Dionne   MoveAssignable& operator=(MoveAssignable&&) = default;
74*618862e8SLouis Dionne };
75*618862e8SLouis Dionne 
76*618862e8SLouis Dionne struct CopyAssignable
77*618862e8SLouis Dionne {
78*618862e8SLouis Dionne   CopyAssignable& operator=(CopyAssignable const&) = default;
79*618862e8SLouis Dionne   CopyAssignable& operator=(CopyAssignable&&) = delete;
80*618862e8SLouis Dionne };
81*618862e8SLouis Dionne 
82a0839b14SLouis Dionne struct NothrowMoveAssignable
83a0839b14SLouis Dionne {
operator =NothrowMoveAssignable84a0839b14SLouis Dionne     NothrowMoveAssignable& operator=(NothrowMoveAssignable&&) noexcept { return *this; }
85a0839b14SLouis Dionne };
86a0839b14SLouis Dionne 
87a0839b14SLouis Dionne struct PotentiallyThrowingMoveAssignable
88a0839b14SLouis Dionne {
operator =PotentiallyThrowingMoveAssignable89a0839b14SLouis Dionne     PotentiallyThrowingMoveAssignable& operator=(PotentiallyThrowingMoveAssignable&&) { return *this; }
9082c4701dSzoecarver };
9182c4701dSzoecarver 
main(int,char **)922df59c50SJF Bastien int main(int, char**)
935a83710eSEric Fiselier {
945a83710eSEric Fiselier     {
95a0d87857SStephan T. Lavavej         typedef std::pair<long, std::unique_ptr<D>> T0;
96a0d87857SStephan T. Lavavej         typedef std::tuple<long long, std::unique_ptr<B>> T1;
97a0d87857SStephan T. Lavavej         T0 t0(2, std::unique_ptr<D>(new D(3)));
985a83710eSEric Fiselier         T1 t1;
995a83710eSEric Fiselier         t1 = std::move(t0);
1005a83710eSEric Fiselier         assert(std::get<0>(t1) == 2);
1015a83710eSEric Fiselier         assert(std::get<1>(t1)->id_ == 3);
1025a83710eSEric Fiselier     }
10382c4701dSzoecarver     {
104a0839b14SLouis Dionne         using T = std::tuple<int, NonAssignable>;
105a0839b14SLouis Dionne         using P = std::pair<int, NonAssignable>;
10682c4701dSzoecarver         static_assert(!std::is_assignable<T&, P&&>::value, "");
10782c4701dSzoecarver     }
10882c4701dSzoecarver     {
10982c4701dSzoecarver       using T = std::tuple<int, int, int>;
11082c4701dSzoecarver       using P = std::pair<int, int>;
11182c4701dSzoecarver       static_assert(!std::is_assignable<T&, P&&>::value, "");
11282c4701dSzoecarver     }
113a0839b14SLouis Dionne     {
114a0839b14SLouis Dionne         typedef std::tuple<NothrowMoveAssignable, long> Tuple;
115a0839b14SLouis Dionne         typedef std::pair<NothrowMoveAssignable, int> Pair;
116a0839b14SLouis Dionne         static_assert(std::is_nothrow_assignable<Tuple&, Pair&&>::value, "");
117a0839b14SLouis Dionne         static_assert(!std::is_assignable<Tuple&, Pair const&&>::value, "");
118a0839b14SLouis Dionne     }
119a0839b14SLouis Dionne     {
120a0839b14SLouis Dionne         typedef std::tuple<PotentiallyThrowingMoveAssignable, long> Tuple;
121a0839b14SLouis Dionne         typedef std::pair<PotentiallyThrowingMoveAssignable, int> Pair;
122a0839b14SLouis Dionne         static_assert(std::is_assignable<Tuple&, Pair&&>::value, "");
123a0839b14SLouis Dionne         static_assert(!std::is_nothrow_assignable<Tuple&, Pair&&>::value, "");
124a0839b14SLouis Dionne         static_assert(!std::is_assignable<Tuple&, Pair const&&>::value, "");
125a0839b14SLouis Dionne     }
126*618862e8SLouis Dionne     {
127*618862e8SLouis Dionne         // We assign through the reference and don't move out of the incoming ref,
128*618862e8SLouis Dionne         // so this doesn't work (but would if the type were CopyAssignable).
129*618862e8SLouis Dionne         {
130*618862e8SLouis Dionne             using T = std::tuple<MoveAssignable&, int>;
131*618862e8SLouis Dionne             using P = std::pair<MoveAssignable&, int>;
132*618862e8SLouis Dionne             static_assert(!std::is_assignable<T&, P&&>::value, "");
133*618862e8SLouis Dionne         }
134*618862e8SLouis Dionne 
135*618862e8SLouis Dionne         // ... works if it's CopyAssignable
136*618862e8SLouis Dionne         {
137*618862e8SLouis Dionne             using T = std::tuple<CopyAssignable&, int>;
138*618862e8SLouis Dionne             using P = std::pair<CopyAssignable&, int>;
139*618862e8SLouis Dionne             static_assert(std::is_assignable<T&, P&&>::value, "");
140*618862e8SLouis Dionne         }
141*618862e8SLouis Dionne 
142*618862e8SLouis Dionne         // For rvalue-references, we can move-assign if the type is MoveAssignable
143*618862e8SLouis Dionne         // or CopyAssignable (since in the worst case the move will decay into a copy).
144*618862e8SLouis Dionne         {
145*618862e8SLouis Dionne             using T1 = std::tuple<MoveAssignable&&, int>;
146*618862e8SLouis Dionne             using P1 = std::pair<MoveAssignable&&, int>;
147*618862e8SLouis Dionne             static_assert(std::is_assignable<T1&, P1&&>::value, "");
148*618862e8SLouis Dionne 
149*618862e8SLouis Dionne             using T2 = std::tuple<CopyAssignable&&, int>;
150*618862e8SLouis Dionne             using P2 = std::pair<CopyAssignable&&, int>;
151*618862e8SLouis Dionne             static_assert(std::is_assignable<T2&, P2&&>::value, "");
152*618862e8SLouis Dionne         }
153*618862e8SLouis Dionne 
154*618862e8SLouis Dionne         // In all cases, we can't move-assign if the types are not assignable,
155*618862e8SLouis Dionne         // since we assign through the reference.
156*618862e8SLouis Dionne         {
157*618862e8SLouis Dionne             using T1 = std::tuple<NonAssignable&, int>;
158*618862e8SLouis Dionne             using P1 = std::pair<NonAssignable&, int>;
159*618862e8SLouis Dionne             static_assert(!std::is_assignable<T1&, P1&&>::value, "");
160*618862e8SLouis Dionne 
161*618862e8SLouis Dionne             using T2 = std::tuple<NonAssignable&&, int>;
162*618862e8SLouis Dionne             using P2 = std::pair<NonAssignable&&, int>;
163*618862e8SLouis Dionne             static_assert(!std::is_assignable<T2&, P2&&>::value, "");
164*618862e8SLouis Dionne         }
165*618862e8SLouis Dionne     }
166*618862e8SLouis Dionne     {
167*618862e8SLouis Dionne         // Make sure that we don't incorrectly move out of the source's reference.
168*618862e8SLouis Dionne         using Dest = std::tuple<TrackMove, int>;
169*618862e8SLouis Dionne         using Source = std::pair<TrackMove&, int>;
170*618862e8SLouis Dionne         TrackMove track{3};
171*618862e8SLouis Dionne         Source src(track, 4);
172*618862e8SLouis Dionne         assert(!track.moved_from);
173*618862e8SLouis Dionne 
174*618862e8SLouis Dionne         Dest dst;
175*618862e8SLouis Dionne         dst = std::move(src); // here we should make a copy
176*618862e8SLouis Dionne         assert(!track.moved_from);
177*618862e8SLouis Dionne         assert(std::get<0>(dst).value == 3);
178*618862e8SLouis Dionne     }
179*618862e8SLouis Dionne     {
180*618862e8SLouis Dionne         // But we do move out of the source's reference if it's a rvalue ref
181*618862e8SLouis Dionne         using Dest = std::tuple<TrackMove, int>;
182*618862e8SLouis Dionne         using Source = std::pair<TrackMove&&, int>;
183*618862e8SLouis Dionne         TrackMove track{3};
184*618862e8SLouis Dionne         Source src(std::move(track), 4);
185*618862e8SLouis Dionne         assert(!track.moved_from); // we just took a reference
186*618862e8SLouis Dionne 
187*618862e8SLouis Dionne         Dest dst;
188*618862e8SLouis Dionne         dst = std::move(src);
189*618862e8SLouis Dionne         assert(track.moved_from);
190*618862e8SLouis Dionne         assert(std::get<0>(dst).value == 3);
191*618862e8SLouis Dionne     }
192*618862e8SLouis Dionne     {
193*618862e8SLouis Dionne         // If the pair holds a value, then we move out of it too
194*618862e8SLouis Dionne         using Dest = std::tuple<TrackMove, int>;
195*618862e8SLouis Dionne         using Source = std::pair<TrackMove, int>;
196*618862e8SLouis Dionne         Source src(TrackMove{3}, 4);
197*618862e8SLouis Dionne         Dest dst;
198*618862e8SLouis Dionne         dst = std::move(src);
199*618862e8SLouis Dionne         assert(src.first.moved_from);
200*618862e8SLouis Dionne         assert(std::get<0>(dst).value == 3);
201*618862e8SLouis Dionne     }
2022df59c50SJF Bastien 
2032df59c50SJF Bastien     return 0;
2045a83710eSEric Fiselier }
205