xref: /llvm-project/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_rv_pair.pass.cpp (revision 618862e89a022b2e8f73a62bed7c91654060dbab)
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 // UNSUPPORTED: c++03
10 
11 // <utility>
12 
13 // template <class T1, class T2> struct pair
14 
15 // pair& operator=(pair&& p);
16 
17 #include <utility>
18 #include <memory>
19 #include <cassert>
20 
21 #include "test_macros.h"
22 #include "archetypes.h"
23 
24 struct CountAssign {
25   int copied = 0;
26   int moved = 0;
27   TEST_CONSTEXPR_CXX20 CountAssign() = default;
operator =CountAssign28   TEST_CONSTEXPR_CXX20 CountAssign& operator=(CountAssign const&) {
29     ++copied;
30     return *this;
31   }
operator =CountAssign32   TEST_CONSTEXPR_CXX20 CountAssign& operator=(CountAssign&&) {
33     ++moved;
34     return *this;
35   }
36 };
37 
38 struct NotAssignable {
39   NotAssignable& operator=(NotAssignable const&) = delete;
40   NotAssignable& operator=(NotAssignable&&) = delete;
41 };
42 
43 struct MoveAssignable {
44   MoveAssignable& operator=(MoveAssignable const&) = delete;
45   MoveAssignable& operator=(MoveAssignable&&) = default;
46 };
47 
48 struct CopyAssignable {
49   CopyAssignable& operator=(CopyAssignable const&) = default;
50   CopyAssignable& operator=(CopyAssignable&&) = delete;
51 };
52 
test()53 TEST_CONSTEXPR_CXX20 bool test() {
54   {
55     typedef std::pair<ConstexprTestTypes::MoveOnly, int> P;
56     P p1(3, 4);
57     P p2;
58     p2 = std::move(p1);
59     assert(p2.first.value == 3);
60     assert(p2.second == 4);
61   }
62   {
63     using P = std::pair<int&, int&&>;
64     int x = 42;
65     int y = 101;
66     int x2 = -1;
67     int y2 = 300;
68     P p1(x, std::move(y));
69     P p2(x2, std::move(y2));
70     p1 = std::move(p2);
71     assert(p1.first == x2);
72     assert(p1.second == y2);
73   }
74   {
75     using P = std::pair<int, ConstexprTestTypes::DefaultOnly>;
76     static_assert(!std::is_move_assignable<P>::value, "");
77   }
78   {
79     // The move decays to the copy constructor
80     using P = std::pair<CountAssign, ConstexprTestTypes::CopyOnly>;
81     static_assert(std::is_move_assignable<P>::value, "");
82     P p;
83     P p2;
84     p = std::move(p2);
85     assert(p.first.moved == 0);
86     assert(p.first.copied == 1);
87     assert(p2.first.moved == 0);
88     assert(p2.first.copied == 0);
89   }
90   {
91     using P = std::pair<CountAssign, ConstexprTestTypes::MoveOnly>;
92     static_assert(std::is_move_assignable<P>::value, "");
93     P p;
94     P p2;
95     p = std::move(p2);
96     assert(p.first.moved == 1);
97     assert(p.first.copied == 0);
98     assert(p2.first.moved == 0);
99     assert(p2.first.copied == 0);
100   }
101   {
102     using P1 = std::pair<int, NotAssignable>;
103     using P2 = std::pair<NotAssignable, int>;
104     using P3 = std::pair<NotAssignable, NotAssignable>;
105     static_assert(!std::is_move_assignable<P1>::value, "");
106     static_assert(!std::is_move_assignable<P2>::value, "");
107     static_assert(!std::is_move_assignable<P3>::value, "");
108   }
109   {
110     // We assign through the reference and don't move out of the incoming ref,
111     // so this doesn't work (but would if the type were CopyAssignable).
112     using P1 = std::pair<MoveAssignable&, int>;
113     static_assert(!std::is_move_assignable<P1>::value, "");
114 
115     // ... works if it's CopyAssignable
116     using P2 = std::pair<CopyAssignable&, int>;
117     static_assert(std::is_move_assignable<P2>::value, "");
118 
119     // For rvalue-references, we can move-assign if the type is MoveAssignable
120     // or CopyAssignable (since in the worst case the move will decay into a copy).
121     using P3 = std::pair<MoveAssignable&&, int>;
122     using P4 = std::pair<CopyAssignable&&, int>;
123     static_assert(std::is_move_assignable<P3>::value, "");
124     static_assert(std::is_move_assignable<P4>::value, "");
125 
126     // In all cases, we can't move-assign if the types are not assignable,
127     // since we assign through the reference.
128     using P5 = std::pair<NotAssignable&, int>;
129     using P6 = std::pair<NotAssignable&&, int>;
130     static_assert(!std::is_move_assignable<P5>::value, "");
131     static_assert(!std::is_move_assignable<P6>::value, "");
132   }
133   return true;
134 }
135 
main(int,char **)136 int main(int, char**) {
137   test();
138 #if TEST_STD_VER >= 20
139   static_assert(test());
140 #endif
141 
142   return 0;
143 }
144