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// <expected>
12
13// template<class F> constexpr auto or_else(F&& f) &;
14// template<class F> constexpr auto or_else(F&& f) const &;
15// template<class F> constexpr auto or_else(F&& f) &&;
16// template<class F> constexpr auto or_else(F&& f) const &&;
17
18#include <cassert>
19#include <concepts>
20#include <expected>
21#include <memory>
22#include <type_traits>
23#include <utility>
24
25#include "../../types.h"
26
27struct LVal {
28 constexpr std::expected<int, int> operator()(int&) { return 1; }
29 std::expected<int, int> operator()(const int&) = delete;
30 std::expected<int, int> operator()(int&&) = delete;
31 std::expected<int, int> operator()(const int&&) = delete;
32};
33
34struct CLVal {
35 std::expected<int, int> operator()(int&) = delete;
36 constexpr std::expected<int, int> operator()(const int&) { return 1; }
37 std::expected<int, int> operator()(int&&) = delete;
38 std::expected<int, int> operator()(const int&&) = delete;
39};
40
41struct RVal {
42 std::expected<int, int> operator()(int&) = delete;
43 std::expected<int, int> operator()(const int&) = delete;
44 constexpr std::expected<int, int> operator()(int&&) { return 1; }
45 std::expected<int, int> operator()(const int&&) = delete;
46};
47
48struct CRVal {
49 std::expected<int, int> operator()(int&) = delete;
50 std::expected<int, int> operator()(const int&) = delete;
51 std::expected<int, int> operator()(int&&) = delete;
52 constexpr std::expected<int, int> operator()(const int&&) { return 1; }
53};
54
55struct RefQual {
56 constexpr std::expected<int, int> operator()(int) & { return 1; }
57 std::expected<int, int> operator()(int) const& = delete;
58 std::expected<int, int> operator()(int) && = delete;
59 std::expected<int, int> operator()(int) const&& = delete;
60};
61
62struct CRefQual {
63 std::expected<int, int> operator()(int) & = delete;
64 constexpr std::expected<int, int> operator()(int) const& { return 1; }
65 std::expected<int, int> operator()(int) && = delete;
66 std::expected<int, int> operator()(int) const&& = delete;
67};
68
69struct RVRefQual {
70 std::expected<int, int> operator()(int) & = delete;
71 std::expected<int, int> operator()(int) const& = delete;
72 constexpr std::expected<int, int> operator()(int) && { return 1; }
73 std::expected<int, int> operator()(int) const&& = delete;
74};
75
76struct RVCRefQual {
77 std::expected<int, int> operator()(int) & = delete;
78 std::expected<int, int> operator()(int) const& = delete;
79 std::expected<int, int> operator()(int) && = delete;
80 constexpr std::expected<int, int> operator()(int) const&& { return 1; }
81};
82
83template <class E, class F>
84concept has_or_else =
85 requires(E&& e, F&& f) {
86 { std::forward<E>(e).or_else(std::forward<F>(f)) };
87 };
88// clang-format off
89// [LWG 3877] https://cplusplus.github.io/LWG/issue3877, check constraint failing but not compile error inside the function body.
90static_assert(!has_or_else<const std::expected<std::unique_ptr<int>, int>&, int()>);
91static_assert(!has_or_else<const std::expected<std::unique_ptr<int>, int>&&, int()>);
92
93// [LWG 3983] https://cplusplus.github.io/LWG/issue3938, check std::expected monadic ops well-formed with move-only error_type.
94static_assert(has_or_else<std::expected<int, MoveOnlyErrorType>&, std::expected<int, int>(MoveOnlyErrorType &)>);
95static_assert(has_or_else<const std::expected<int, MoveOnlyErrorType>&, std::expected<int, int>(const MoveOnlyErrorType &)>);
96static_assert(has_or_else<std::expected<int, MoveOnlyErrorType>&&, std::expected<int, int>(MoveOnlyErrorType&&)>);
97static_assert(has_or_else<const std::expected<int, MoveOnlyErrorType>&&, std::expected<int, int>(const MoveOnlyErrorType&&)>);
98
99constexpr void test_val_types() {
100 // Test & overload
101 {
102 // Without & qualifier on F's operator()
103 {
104 std::expected<int, int> e(std::unexpected<int>(0));
105 std::same_as<std::expected<int, int>> decltype(auto) val = e.or_else(LVal{});
106 assert(val == 1);
107 }
108
109 // With & qualifier on F's operator
110 {
111 std::expected<int, int> e(std::unexpected<int>(0));
112 RefQual l{};
113 std::same_as<std::expected<int, int>> decltype(auto) val = e.or_else(l);
114 assert(val == 1);
115 }
116 }
117
118 // Test const& overload
119 {
120 // Without const& qualifier on F's operator()
121 {
122 const std::expected<int, int> e(std::unexpected<int>(0));
123 std::same_as<std::expected<int, int>> decltype(auto) val = e.or_else(CLVal{});
124 assert(val == 1);
125 }
126
127 // With const& qualifier on F's operator()
128 {
129 const std::expected<int, int> e(std::unexpected<int>(0));
130 const CRefQual l{};
131 std::same_as<std::expected<int, int>> decltype(auto) val = e.or_else(l);
132 assert(val == 1);
133 }
134 }
135
136 // Test && overload
137 {
138 // Without && qualifier on F's operator()
139 {
140 std::expected<int, int> e(std::unexpected<int>(0));
141 std::same_as<std::expected<int, int>> decltype(auto) val = std::move(e).or_else(RVal{});
142 assert(val == 1);
143 }
144
145 // With && qualifier on F's operator()
146 {
147 std::expected<int, int> e(std::unexpected<int>(0));
148 std::same_as<std::expected<int, int>> decltype(auto) val = std::move(e).or_else(RVRefQual{});
149 assert(val == 1);
150 }
151 }
152
153 // Test const&& overload
154 {
155 // Without const&& qualifier on F's operator()
156 {
157 const std::expected<int, int> e(std::unexpected<int>(0));
158 std::same_as<std::expected<int, int>> decltype(auto) val = std::move(e).or_else(CRVal{});
159 assert(val == 1);
160 }
161
162 // With const&& qualifier on F's operator()
163 {
164 const std::expected<int, int> e(std::unexpected<int>(0));
165 const RVCRefQual l{};
166 std::same_as<std::expected<int, int>> decltype(auto) val = std::move(e).or_else(std::move(l));
167 assert(val == 1);
168 }
169 }
170}
171// clang-format on
172
173struct NonConst {
174 std::expected<int, int> non_const() { return std::expected<int, int>(std::unexpect, 1); }
175};
176
177// check that the lambda body is not instantiated during overload resolution
178constexpr void test_sfinae() {
179 std::expected<int, NonConst> e{1};
180 auto l = [](auto&& x) { return x.non_const(); };
181 e.or_else(l);
182 std::move(e).or_else(l);
183}
184
185constexpr void test_move_only_error_type() {
186 // Test &
187 {
188 std::expected<int, MoveOnlyErrorType> e;
189 auto l = [](MoveOnlyErrorType&) { return std::expected<int, int>{}; };
190 e.or_else(l);
191 }
192
193 // Test const&
194 {
195 const std::expected<int, MoveOnlyErrorType> e;
196 auto l = [](const MoveOnlyErrorType&) { return std::expected<int, int>{}; };
197 e.or_else(l);
198 }
199
200 // Test &&
201 {
202 std::expected<int, MoveOnlyErrorType> e;
203 auto l = [](MoveOnlyErrorType&&) { return std::expected<int, int>{}; };
204 std::move(e).or_else(l);
205 }
206
207 // Test const&&
208 {
209 const std::expected<int, MoveOnlyErrorType> e;
210 auto l = [](const MoveOnlyErrorType&&) { return std::expected<int, int>{}; };
211 std::move(e).or_else(l);
212 }
213}
214
215constexpr bool test() {
216 test_sfinae();
217 test_val_types();
218 test_move_only_error_type();
219
220 std::expected<int, int> e(1);
221 const auto& ce = e;
222
223 const auto never_called = [](int) {
224 assert(false);
225 return std::expected<int, int>();
226 };
227
228 e.or_else(never_called);
229 std::move(e).or_else(never_called);
230 ce.or_else(never_called);
231 std::move(ce).or_else(never_called);
232 return true;
233}
234
235int main(int, char**) {
236 test();
237 static_assert(test());
238
239 return 0;
240}
241

source code of libcxx/test/std/utilities/expected/expected.expected/monadic/or_else.pass.cpp