xref: /llvm-project/libcxx/test/std/utilities/optional/optional.monadic/and_then.pass.cpp (revision c31cf74c3c3ca8ddd6d695ae7591f6cbfee54a6a)
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 // <optional>
11 
12 // template<class F> constexpr auto and_then(F&&) &;
13 // template<class F> constexpr auto and_then(F&&) &&;
14 // template<class F> constexpr auto and_then(F&&) const&;
15 // template<class F> constexpr auto and_then(F&&) const&&;
16 
17 #include <cassert>
18 #include <optional>
19 
20 #include "test_macros.h"
21 
22 struct LVal {
23   constexpr std::optional<int> operator()(int&) { return 1; }
24   std::optional<int> operator()(const int&) = delete;
25   std::optional<int> operator()(int&&) = delete;
26   std::optional<int> operator()(const int&&) = delete;
27 };
28 
29 struct CLVal {
30   std::optional<int> operator()(int&) = delete;
31   constexpr std::optional<int> operator()(const int&) { return 1; }
32   std::optional<int> operator()(int&&) = delete;
33   std::optional<int> operator()(const int&&) = delete;
34 };
35 
36 struct RVal {
37   std::optional<int> operator()(int&) = delete;
38   std::optional<int> operator()(const int&) = delete;
39   constexpr std::optional<int> operator()(int&&) { return 1; }
40   std::optional<int> operator()(const int&&) = delete;
41 };
42 
43 struct CRVal {
44   std::optional<int> operator()(int&) = delete;
45   std::optional<int> operator()(const int&) = delete;
46   std::optional<int> operator()(int&&) = delete;
47   constexpr std::optional<int> operator()(const int&&) { return 1; }
48 };
49 
50 struct RefQual {
51   constexpr std::optional<int> operator()(int) & { return 1; }
52   std::optional<int> operator()(int) const& = delete;
53   std::optional<int> operator()(int) && = delete;
54   std::optional<int> operator()(int) const&& = delete;
55 };
56 
57 struct CRefQual {
58   std::optional<int> operator()(int) & = delete;
59   constexpr std::optional<int> operator()(int) const& { return 1; }
60   std::optional<int> operator()(int) && = delete;
61   std::optional<int> operator()(int) const&& = delete;
62 };
63 
64 struct RVRefQual {
65   std::optional<int> operator()(int) & = delete;
66   std::optional<int> operator()(int) const& = delete;
67   constexpr std::optional<int> operator()(int) && { return 1; }
68   std::optional<int> operator()(int) const&& = delete;
69 };
70 
71 struct RVCRefQual {
72   std::optional<int> operator()(int) & = delete;
73   std::optional<int> operator()(int) const& = delete;
74   std::optional<int> operator()(int) && = delete;
75   constexpr std::optional<int> operator()(int) const&& { return 1; }
76 };
77 
78 struct NOLVal {
79   constexpr std::optional<int> operator()(int&) { return std::nullopt; }
80   std::optional<int> operator()(const int&) = delete;
81   std::optional<int> operator()(int&&) = delete;
82   std::optional<int> operator()(const int&&) = delete;
83 };
84 
85 struct NOCLVal {
86   std::optional<int> operator()(int&) = delete;
87   constexpr std::optional<int> operator()(const int&) { return std::nullopt; }
88   std::optional<int> operator()(int&&) = delete;
89   std::optional<int> operator()(const int&&) = delete;
90 };
91 
92 struct NORVal {
93   std::optional<int> operator()(int&) = delete;
94   std::optional<int> operator()(const int&) = delete;
95   constexpr std::optional<int> operator()(int&&) { return std::nullopt; }
96   std::optional<int> operator()(const int&&) = delete;
97 };
98 
99 struct NOCRVal {
100   std::optional<int> operator()(int&) = delete;
101   std::optional<int> operator()(const int&) = delete;
102   std::optional<int> operator()(int&&) = delete;
103   constexpr std::optional<int> operator()(const int&&) { return std::nullopt; }
104 };
105 
106 struct NORefQual {
107   constexpr std::optional<int> operator()(int) & { return std::nullopt; }
108   std::optional<int> operator()(int) const& = delete;
109   std::optional<int> operator()(int) && = delete;
110   std::optional<int> operator()(int) const&& = delete;
111 };
112 
113 struct NOCRefQual {
114   std::optional<int> operator()(int) & = delete;
115   constexpr std::optional<int> operator()(int) const& { return std::nullopt; }
116   std::optional<int> operator()(int) && = delete;
117   std::optional<int> operator()(int) const&& = delete;
118 };
119 
120 struct NORVRefQual {
121   std::optional<int> operator()(int) & = delete;
122   std::optional<int> operator()(int) const& = delete;
123   constexpr std::optional<int> operator()(int) && { return std::nullopt; }
124   std::optional<int> operator()(int) const&& = delete;
125 };
126 
127 struct NORVCRefQual {
128   std::optional<int> operator()(int) & = delete;
129   std::optional<int> operator()(int) const& = delete;
130   std::optional<int> operator()(int) && = delete;
131   constexpr std::optional<int> operator()(int) const&& { return std::nullopt; }
132 };
133 
134 struct NoCopy {
135   NoCopy() = default;
136   NoCopy(const NoCopy&) { assert(false); }
137   std::optional<int> operator()(const NoCopy&&) { return 1; }
138 };
139 
140 struct NonConst {
141   std::optional<int> non_const() { return 1; }
142 };
143 
144 constexpr void test_val_types() {
145   // Test & overload
146   {
147     // Without & qualifier on F's operator()
148     {
149       std::optional<int> i{0};
150       assert(i.and_then(LVal{}) == 1);
151       assert(i.and_then(NOLVal{}) == std::nullopt);
152       ASSERT_SAME_TYPE(decltype(i.and_then(LVal{})), std::optional<int>);
153     }
154 
155     //With & qualifier on F's operator()
156     {
157       std::optional<int> i{0};
158       RefQual l{};
159       assert(i.and_then(l) == 1);
160       NORefQual nl{};
161       assert(i.and_then(nl) == std::nullopt);
162       ASSERT_SAME_TYPE(decltype(i.and_then(l)), std::optional<int>);
163     }
164   }
165 
166   // Test const& overload
167   {
168     // Without & qualifier on F's operator()
169     {
170       const std::optional<int> i{0};
171       assert(i.and_then(CLVal{}) == 1);
172       assert(i.and_then(NOCLVal{}) == std::nullopt);
173       ASSERT_SAME_TYPE(decltype(i.and_then(CLVal{})), std::optional<int>);
174     }
175 
176     //With & qualifier on F's operator()
177     {
178       const std::optional<int> i{0};
179       const CRefQual l{};
180       assert(i.and_then(l) == 1);
181       const NOCRefQual nl{};
182       assert(i.and_then(nl) == std::nullopt);
183       ASSERT_SAME_TYPE(decltype(i.and_then(l)), std::optional<int>);
184     }
185   }
186 
187   // Test && overload
188   {
189     // Without & qualifier on F's operator()
190     {
191       std::optional<int> i{0};
192       assert(std::move(i).and_then(RVal{}) == 1);
193       assert(std::move(i).and_then(NORVal{}) == std::nullopt);
194       ASSERT_SAME_TYPE(decltype(std::move(i).and_then(RVal{})), std::optional<int>);
195     }
196 
197     //With & qualifier on F's operator()
198     {
199       std::optional<int> i{0};
200       assert(i.and_then(RVRefQual{}) == 1);
201       assert(i.and_then(NORVRefQual{}) == std::nullopt);
202       ASSERT_SAME_TYPE(decltype(i.and_then(RVRefQual{})), std::optional<int>);
203     }
204   }
205 
206   // Test const&& overload
207   {
208     // Without & qualifier on F's operator()
209     {
210       const std::optional<int> i{0};
211       assert(std::move(i).and_then(CRVal{}) == 1);
212       assert(std::move(i).and_then(NOCRVal{}) == std::nullopt);
213       ASSERT_SAME_TYPE(decltype(std::move(i).and_then(CRVal{})), std::optional<int>);
214     }
215 
216     //With & qualifier on F's operator()
217     {
218       const std::optional<int> i{0};
219       const RVCRefQual l{};
220       assert(i.and_then(std::move(l)) == 1);
221       const NORVCRefQual nl{};
222       assert(i.and_then(std::move(nl)) == std::nullopt);
223       ASSERT_SAME_TYPE(decltype(i.and_then(std::move(l))), std::optional<int>);
224     }
225   }
226 }
227 
228 // check that the lambda body is not instantiated during overload resolution
229 constexpr void test_sfinae() {
230   std::optional<NonConst> opt{};
231   auto l = [](auto&& x) { return x.non_const(); };
232   opt.and_then(l);
233   std::move(opt).and_then(l);
234 }
235 
236 constexpr bool test() {
237   test_val_types();
238   std::optional<int> opt{};
239   const auto& copt = opt;
240 
241   const auto never_called = [](int) {
242     assert(false);
243     return std::optional<int>{};
244   };
245 
246   opt.and_then(never_called);
247   std::move(opt).and_then(never_called);
248   copt.and_then(never_called);
249   std::move(copt).and_then(never_called);
250 
251   std::optional<NoCopy> nc;
252   const auto& cnc = nc;
253   std::move(cnc).and_then(NoCopy{});
254   std::move(nc).and_then(NoCopy{});
255 
256   return true;
257 }
258 
259 int main(int, char**) {
260   test();
261   static_assert(test());
262   return 0;
263 }
264