xref: /llvm-project/libcxx/test/std/utilities/expected/expected.expected/monadic/transform.pass.cpp (revision cb4433b677a06ecbb3112f39d24b28f19b0d2626)
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, c++11, c++14, c++17, c++20
10 
11 // GCC has a issue for `Guaranteed copy elision for potentially-overlapping non-static data members`,
12 // please refer to: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108333
13 // XFAIL: gcc-14
14 
15 // <expected>
16 
17 // template<class F> constexpr auto transform(F&& f) &;
18 // template<class F> constexpr auto transform(F&& f) const &;
19 // template<class F> constexpr auto transform(F&& f) &&;
20 // template<class F> constexpr auto transform(F&& f) const &&;
21 
22 #include <expected>
23 #include <concepts>
24 #include <cassert>
25 #include <memory>
26 #include <type_traits>
27 #include <utility>
28 
29 #include "../../types.h"
30 
31 struct LVal {
32   constexpr int operator()(int&) { return 1; }
33   int operator()(const int&)  = delete;
34   int operator()(int&&)       = delete;
35   int operator()(const int&&) = delete;
36 };
37 
38 struct CLVal {
39   int operator()(int&) = delete;
40   constexpr int operator()(const int&) { return 1; }
41   int operator()(int&&)       = delete;
42   int operator()(const int&&) = delete;
43 };
44 
45 struct RVal {
46   int operator()(int&)       = delete;
47   int operator()(const int&) = delete;
48   constexpr int operator()(int&&) { return 1; }
49   int operator()(const int&&) = delete;
50 };
51 
52 struct CRVal {
53   int operator()(int&)       = delete;
54   int operator()(const int&) = delete;
55   int operator()(int&&)      = delete;
56   constexpr int operator()(const int&&) { return 1; }
57 };
58 
59 struct RefQual {
60   constexpr int operator()(int) & { return 1; }
61   int operator()(int) const&  = delete;
62   int operator()(int) &&      = delete;
63   int operator()(int) const&& = delete;
64 };
65 
66 struct CRefQual {
67   int operator()(int) & = delete;
68   constexpr int operator()(int) const& { return 1; }
69   int operator()(int) &&      = delete;
70   int operator()(int) const&& = delete;
71 };
72 
73 struct RVRefQual {
74   int operator()(int) &      = delete;
75   int operator()(int) const& = delete;
76   constexpr int operator()(int) && { return 1; }
77   int operator()(int) const&& = delete;
78 };
79 
80 struct RVCRefQual {
81   int operator()(int) &      = delete;
82   int operator()(int) const& = delete;
83   int operator()(int) &&     = delete;
84   constexpr int operator()(int) const&& { return 1; }
85 };
86 
87 struct NonCopy {
88   int value;
89   constexpr explicit NonCopy(int val) : value(val) {}
90   NonCopy(const NonCopy&) = delete;
91 };
92 
93 struct NonConst {
94   int non_const() { return 1; }
95 };
96 
97 template <class E, class F>
98 concept has_transform =
99     requires(E&& e, F&& f) {
100       { std::forward<E>(e).transform(std::forward<F>(f)) };
101     };
102 
103 // clang-format off
104 // [LWG 3877] https://cplusplus.github.io/LWG/issue3877, check constraint failing but not compile error inside the function body.
105 static_assert(!has_transform<const std::expected<int, std::unique_ptr<int>>&, int()>);
106 static_assert(!has_transform<const std::expected<int, std::unique_ptr<int>>&&, int()>);
107 
108 // [LWG 3983] https://cplusplus.github.io/LWG/issue3938, check std::expected monadic ops well-formed with move-only error_type.
109 // There are no effects for `&` and `const &` overload, because the constraints requires is_constructible_v<E, decltype(error())> is true.
110 static_assert(has_transform<std::expected<int, MoveOnlyErrorType>&&, int(int)>);
111 static_assert(has_transform<const std::expected<int, MoveOnlyErrorType>&&, int(const int)>);
112 
113 constexpr void test_val_types() {
114   // Test & overload
115   {
116     // Without & qualifier on F's operator()
117     {
118       std::expected<int, int> e(0);
119       std::same_as<std::expected<int, int>> decltype(auto) val = e.transform(LVal{});
120       assert(val == 1);
121     }
122 
123     // With & qualifier on F's operator()
124     {
125       std::expected<int, int> e(0);
126       RefQual l{};
127       std::same_as<std::expected<int, int>> decltype(auto) val = e.transform(l);
128       assert(val == 1);
129     }
130   }
131 
132   // Test const& overload
133   {
134     // Without & qualifier on F's operator()
135     {
136       const std::expected<int, int> e(0);
137       std::same_as<std::expected<int, int>> decltype(auto) val = e.transform(CLVal{});
138       assert(val == 1);
139     }
140 
141     // With & qualifier on F's operator()
142     {
143       const std::expected<int, int> e(0);
144       const CRefQual l{};
145       std::same_as<std::expected<int, int>> decltype(auto) val = e.transform(l);
146       assert(val == 1);
147     }
148   }
149 
150   // Test && overload
151   {
152     // Without & qualifier on F's operator()
153     {
154       std::expected<int, int> e(0);
155       std::same_as<std::expected<int, int>> decltype(auto) val = std::move(e).transform(RVal{});
156       assert(val == 1);
157     }
158 
159     // With & qualifier on F's operator()
160     {
161       std::expected<int, int> e(0);
162       std::same_as<std::expected<int, int>> decltype(auto) val = std::move(e).transform(RVRefQual{});
163       assert(val == 1);
164     }
165   }
166 
167   // Test const&& overload
168   {
169     // Without & qualifier on F's operator()
170     {
171       const std::expected<int, int> e(0);
172       std::same_as<std::expected<int, int>> decltype(auto) val = std::move(e).transform(CRVal{});
173       assert(val == 1);
174     }
175 
176     // With & qualifier on F's operator()
177     {
178       const std::expected<int, int> e(0);
179       const RVCRefQual l{};
180       std::same_as<std::expected<int, int>> decltype(auto) val = e.transform(std::move(l));
181       assert(val == 1);
182     }
183   }
184 }
185 // clang-format on
186 
187 constexpr void test_take_val_return_void() {
188   std::expected<int, int> e(1);
189   int val = 0;
190   (void)e.transform([&val]<typename T>(T&&) -> void {
191     static_assert(std::is_same_v<T, int&>);
192     assert(val == 0);
193     val = 1;
194   });
195   assert(val == 1);
196   (void)std::move(e).transform([&val]<typename T>(T&&) -> void {
197     static_assert(std::is_same_v<T, int>);
198     assert(val == 1);
199     val = 2;
200   });
201 
202   const auto& ce = e;
203   assert(val == 2);
204   (void)ce.transform([&val]<typename T>(T&&) -> void {
205     static_assert(std::is_same_v<T, const int&>);
206     assert(val == 2);
207     val = 3;
208   });
209   assert(val == 3);
210   (void)std::move(ce).transform([&val]<typename T>(T&&) -> void {
211     static_assert(std::is_same_v<T, const int>);
212     assert(val == 3);
213     val = 4;
214   });
215   assert(val == 4);
216 }
217 
218 // check val member is direct-non-list-initialized with invoke(std::forward<F>(f), value())
219 constexpr void test_direct_non_list_init() {
220   auto xform = [](int i) { return NonCopy(i); };
221   std::expected<int, int> e(2);
222   std::expected<NonCopy, int> n = e.transform(xform);
223   assert(n.value().value == 2);
224 }
225 
226 // check that the lambda body is not instantiated during overload resolution
227 constexpr void test_sfinae() {
228   std::expected<NonConst, int> e(std::unexpected<int>(2));
229   auto l = [](auto&& x) { return x.non_const(); };
230   (void)e.transform(l);
231   (void)std::move(e).transform(l);
232 
233   std::expected<int, int> e1(std::unexpected<int>(1));
234   const auto& ce1         = e1;
235   const auto never_called = [](int) {
236     assert(false);
237     return std::expected<int, int>();
238   };
239 
240   (void)e1.transform(never_called);
241   (void)std::move(e1).transform(never_called);
242   (void)ce1.transform(never_called);
243   (void)std::move(ce1).transform(never_called);
244 }
245 
246 constexpr void test_move_only_error_type() {
247   // Test &&
248   {
249       std::expected<int, MoveOnlyErrorType> e;
250       auto l = [](int) { return 0; };
251       (void)std::move(e).transform(l);
252   }
253 
254   // Test const&&
255   {
256       const std::expected<int, MoveOnlyErrorType> e;
257       auto l = [](const int) { return 0; };
258       (void)std::move(e).transform(l);
259   }
260 }
261 
262 constexpr bool test() {
263   test_sfinae();
264   test_val_types();
265   test_direct_non_list_init();
266   test_move_only_error_type();
267   return true;
268 }
269 
270 int main(int, char**) {
271   test();
272   static_assert(test());
273 
274   return 0;
275 }
276