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