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