gccrs: Remove obsolete classes and functions.
[official-gcc.git] / gcc / rust / util / expected.h
bloba7ddd55a88d93a53b55068793c3f0aad50db1fe5
1 // clang-format off
2 ///
3 // expected - An implementation of std::expected with extensions
4 // Written in 2017 by Sy Brand (tartanllama@gmail.com, @TartanLlama)
5 //
6 // Documentation available at http://tl.tartanllama.xyz/
7 //
8 // To the extent possible under law, the author(s) have dedicated all
9 // copyright and related and neighboring rights to this software to the
10 // public domain worldwide. This software is distributed without any warranty.
12 // You should have received a copy of the CC0 Public Domain Dedication
13 // along with this software. If not, see
14 // <http://creativecommons.org/publicdomain/zero/1.0/>.
15 ///
17 #ifndef TL_EXPECTED_HPP
18 #define TL_EXPECTED_HPP
20 #define TL_EXPECTED_VERSION_MAJOR 1
21 #define TL_EXPECTED_VERSION_MINOR 1
22 #define TL_EXPECTED_VERSION_PATCH 0
24 #include "rust-system.h"
26 #if defined(__EXCEPTIONS) || defined(_CPPUNWIND)
27 #define TL_EXPECTED_EXCEPTIONS_ENABLED
28 #endif
30 #if (defined(_MSC_VER) && _MSC_VER == 1900)
31 #define TL_EXPECTED_MSVC2015
32 #define TL_EXPECTED_MSVC2015_CONSTEXPR
33 #else
34 #define TL_EXPECTED_MSVC2015_CONSTEXPR constexpr
35 #endif
37 #if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \
38 !defined(__clang__))
39 #define TL_EXPECTED_GCC49
40 #endif
42 #if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && \
43 !defined(__clang__))
44 #define TL_EXPECTED_GCC54
45 #endif
47 #if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 5 && \
48 !defined(__clang__))
49 #define TL_EXPECTED_GCC55
50 #endif
52 #if !defined(TL_ASSERT)
53 //can't have assert in constexpr in C++11 and GCC 4.9 has a compiler bug
54 #if (__cplusplus > 201103L) && !defined(TL_EXPECTED_GCC49)
55 #include <cassert>
56 #define TL_ASSERT(x) assert(x)
57 #else
58 #define TL_ASSERT(x)
59 #endif
60 #endif
62 #if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \
63 !defined(__clang__))
64 // GCC < 5 doesn't support overloading on const&& for member functions
66 #define TL_EXPECTED_NO_CONSTRR
67 // GCC < 5 doesn't support some standard C++11 type traits
68 #define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
69 std::has_trivial_copy_constructor<T>
70 #define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
71 std::has_trivial_copy_assign<T>
73 // This one will be different for GCC 5.7 if it's ever supported
74 #define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
75 std::is_trivially_destructible<T>
77 // GCC 5 < v < 8 has a bug in is_trivially_copy_constructible which breaks
78 // std::vector for non-copyable types
79 #elif (defined(__GNUC__) && __GNUC__ < 8 && !defined(__clang__))
80 #ifndef TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
81 #define TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
82 namespace tl {
83 namespace detail {
84 template <class T>
85 struct is_trivially_copy_constructible
86 : std::is_trivially_copy_constructible<T> {};
87 #ifdef _GLIBCXX_VECTOR
88 template <class T, class A>
89 struct is_trivially_copy_constructible<std::vector<T, A>> : std::false_type {};
90 #endif
91 } // namespace detail
92 } // namespace tl
93 #endif
95 #define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
96 tl::detail::is_trivially_copy_constructible<T>
97 #define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
98 std::is_trivially_copy_assignable<T>
99 #define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
100 std::is_trivially_destructible<T>
101 #else
102 #define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
103 std::is_trivially_copy_constructible<T>
104 #define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
105 std::is_trivially_copy_assignable<T>
106 #define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
107 std::is_trivially_destructible<T>
108 #endif
110 #if __cplusplus > 201103L
111 #define TL_EXPECTED_CXX14
112 #endif
114 #ifdef TL_EXPECTED_GCC49
115 #define TL_EXPECTED_GCC49_CONSTEXPR
116 #else
117 #define TL_EXPECTED_GCC49_CONSTEXPR constexpr
118 #endif
120 #if (__cplusplus == 201103L || defined(TL_EXPECTED_MSVC2015) || \
121 defined(TL_EXPECTED_GCC49))
122 #define TL_EXPECTED_11_CONSTEXPR
123 #else
124 #define TL_EXPECTED_11_CONSTEXPR constexpr
125 #endif
127 namespace tl {
128 template <class T, class E> class expected;
130 #ifndef TL_MONOSTATE_INPLACE_MUTEX
131 #define TL_MONOSTATE_INPLACE_MUTEX
132 class monostate {};
134 struct in_place_t {
135 explicit in_place_t() = default;
137 static constexpr in_place_t in_place{};
138 #endif
140 template <class E> class unexpected {
141 public:
142 static_assert(!std::is_same<E, void>::value, "E must not be void");
144 unexpected() = delete;
145 constexpr explicit unexpected(const E &e) : m_val(e) {}
147 constexpr explicit unexpected(E &&e) : m_val(std::move(e)) {}
149 template <class... Args, typename std::enable_if<std::is_constructible<
150 E, Args &&...>::value>::type * = nullptr>
151 constexpr explicit unexpected(Args &&...args)
152 : m_val(std::forward<Args>(args)...) {}
153 template <
154 class U, class... Args,
155 typename std::enable_if<std::is_constructible<
156 E, std::initializer_list<U> &, Args &&...>::value>::type * = nullptr>
157 constexpr explicit unexpected(std::initializer_list<U> l, Args &&...args)
158 : m_val(l, std::forward<Args>(args)...) {}
160 constexpr const E &value() const & { return m_val; }
161 TL_EXPECTED_11_CONSTEXPR E &value() & { return m_val; }
162 TL_EXPECTED_11_CONSTEXPR E &&value() && { return std::move(m_val); }
163 constexpr const E &&value() const && { return std::move(m_val); }
165 private:
166 E m_val;
169 #ifdef __cpp_deduction_guides
170 template <class E> unexpected(E) -> unexpected<E>;
171 #endif
173 template <class E>
174 constexpr bool operator==(const unexpected<E> &lhs, const unexpected<E> &rhs) {
175 return lhs.value() == rhs.value();
177 template <class E>
178 constexpr bool operator!=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
179 return lhs.value() != rhs.value();
181 template <class E>
182 constexpr bool operator<(const unexpected<E> &lhs, const unexpected<E> &rhs) {
183 return lhs.value() < rhs.value();
185 template <class E>
186 constexpr bool operator<=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
187 return lhs.value() <= rhs.value();
189 template <class E>
190 constexpr bool operator>(const unexpected<E> &lhs, const unexpected<E> &rhs) {
191 return lhs.value() > rhs.value();
193 template <class E>
194 constexpr bool operator>=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
195 return lhs.value() >= rhs.value();
198 template <class E>
199 unexpected<typename std::decay<E>::type> make_unexpected(E &&e) {
200 return unexpected<typename std::decay<E>::type>(std::forward<E>(e));
203 struct unexpect_t {
204 unexpect_t() = default;
206 static constexpr unexpect_t unexpect{};
208 namespace detail {
209 template <typename E>
210 [[noreturn]] TL_EXPECTED_11_CONSTEXPR void throw_exception(E &&e) {
211 #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
212 throw std::forward<E>(e);
213 #else
214 (void)e;
215 #ifdef _MSC_VER
216 gcc_unreachable();
217 #endif
218 #endif
221 #ifndef TL_TRAITS_MUTEX
222 #define TL_TRAITS_MUTEX
223 // C++14-style aliases for brevity
224 template <class T> using remove_const_t = typename std::remove_const<T>::type;
225 template <class T>
226 using remove_reference_t = typename std::remove_reference<T>::type;
227 template <class T> using decay_t = typename std::decay<T>::type;
228 template <bool E, class T = void>
229 using enable_if_t = typename std::enable_if<E, T>::type;
230 template <bool B, class T, class F>
231 using conditional_t = typename std::conditional<B, T, F>::type;
233 // std::conjunction from C++17
234 template <class...> struct conjunction : std::true_type {};
235 template <class B> struct conjunction<B> : B {};
236 template <class B, class... Bs>
237 struct conjunction<B, Bs...>
238 : std::conditional<bool(B::value), conjunction<Bs...>, B>::type {};
240 #if defined(_LIBCPP_VERSION) && __cplusplus == 201103L
241 #define TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
242 #endif
244 // In C++11 mode, there's an issue in libc++'s std::mem_fn
245 // which results in a hard-error when using it in a noexcept expression
246 // in some cases. This is a check to workaround the common failing case.
247 #ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
248 template <class T>
249 struct is_pointer_to_non_const_member_func : std::false_type {};
250 template <class T, class Ret, class... Args>
251 struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...)>
252 : std::true_type {};
253 template <class T, class Ret, class... Args>
254 struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) &>
255 : std::true_type {};
256 template <class T, class Ret, class... Args>
257 struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) &&>
258 : std::true_type {};
259 template <class T, class Ret, class... Args>
260 struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile>
261 : std::true_type {};
262 template <class T, class Ret, class... Args>
263 struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile &>
264 : std::true_type {};
265 template <class T, class Ret, class... Args>
266 struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile &&>
267 : std::true_type {};
269 template <class T> struct is_const_or_const_ref : std::false_type {};
270 template <class T> struct is_const_or_const_ref<T const &> : std::true_type {};
271 template <class T> struct is_const_or_const_ref<T const> : std::true_type {};
272 #endif
274 // std::invoke from C++17
275 // https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround
276 template <
277 typename Fn, typename... Args,
278 #ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
279 typename = enable_if_t<!(is_pointer_to_non_const_member_func<Fn>::value &&
280 is_const_or_const_ref<Args...>::value)>,
281 #endif
282 typename = enable_if_t<std::is_member_pointer<decay_t<Fn>>::value>, int = 0>
283 constexpr auto invoke(Fn &&f, Args &&...args) noexcept(
284 noexcept(std::mem_fn(f)(std::forward<Args>(args)...)))
285 -> decltype(std::mem_fn(f)(std::forward<Args>(args)...)) {
286 return std::mem_fn(f)(std::forward<Args>(args)...);
289 template <typename Fn, typename... Args,
290 typename = enable_if_t<!std::is_member_pointer<decay_t<Fn>>::value>>
291 constexpr auto invoke(Fn &&f, Args &&...args) noexcept(
292 noexcept(std::forward<Fn>(f)(std::forward<Args>(args)...)))
293 -> decltype(std::forward<Fn>(f)(std::forward<Args>(args)...)) {
294 return std::forward<Fn>(f)(std::forward<Args>(args)...);
297 // std::invoke_result from C++17
298 template <class F, class, class... Us> struct invoke_result_impl;
300 template <class F, class... Us>
301 struct invoke_result_impl<
303 decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...), void()),
304 Us...> {
305 using type =
306 decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...));
309 template <class F, class... Us>
310 using invoke_result = invoke_result_impl<F, void, Us...>;
312 template <class F, class... Us>
313 using invoke_result_t = typename invoke_result<F, Us...>::type;
315 #if defined(_MSC_VER) && _MSC_VER <= 1900
316 // TODO make a version which works with MSVC 2015
317 template <class T, class U = T> struct is_swappable : std::true_type {};
319 template <class T, class U = T> struct is_nothrow_swappable : std::true_type {};
320 #else
321 // https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept
322 namespace swap_adl_tests {
323 // if swap ADL finds this then it would call std::swap otherwise (same
324 // signature)
325 struct tag {};
327 template <class T> tag swap(T &, T &);
328 template <class T, std::size_t N> tag swap(T (&a)[N], T (&b)[N]);
330 // helper functions to test if an unqualified swap is possible, and if it
331 // becomes std::swap
332 template <class, class> std::false_type can_swap(...) noexcept(false);
333 template <class T, class U,
334 class = decltype(swap(std::declval<T &>(), std::declval<U &>()))>
335 std::true_type can_swap(int) noexcept(noexcept(swap(std::declval<T &>(),
336 std::declval<U &>())));
338 template <class, class> std::false_type uses_std(...);
339 template <class T, class U>
340 std::is_same<decltype(swap(std::declval<T &>(), std::declval<U &>())), tag>
341 uses_std(int);
343 template <class T>
344 struct is_std_swap_noexcept
345 : std::integral_constant<bool,
346 std::is_nothrow_move_constructible<T>::value &&
347 std::is_nothrow_move_assignable<T>::value> {};
349 template <class T, std::size_t N>
350 struct is_std_swap_noexcept<T[N]> : is_std_swap_noexcept<T> {};
352 template <class T, class U>
353 struct is_adl_swap_noexcept
354 : std::integral_constant<bool, noexcept(can_swap<T, U>(0))> {};
355 } // namespace swap_adl_tests
357 template <class T, class U = T>
358 struct is_swappable
359 : std::integral_constant<
360 bool,
361 decltype(detail::swap_adl_tests::can_swap<T, U>(0))::value &&
362 (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value ||
363 (std::is_move_assignable<T>::value &&
364 std::is_move_constructible<T>::value))> {};
366 template <class T, std::size_t N>
367 struct is_swappable<T[N], T[N]>
368 : std::integral_constant<
369 bool,
370 decltype(detail::swap_adl_tests::can_swap<T[N], T[N]>(0))::value &&
371 (!decltype(detail::swap_adl_tests::uses_std<T[N], T[N]>(
372 0))::value ||
373 is_swappable<T, T>::value)> {};
375 template <class T, class U = T>
376 struct is_nothrow_swappable
377 : std::integral_constant<
378 bool,
379 is_swappable<T, U>::value &&
380 ((decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value &&
381 detail::swap_adl_tests::is_std_swap_noexcept<T>::value) ||
382 (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value &&
383 detail::swap_adl_tests::is_adl_swap_noexcept<T, U>::value))> {};
384 #endif
385 #endif
387 // Trait for checking if a type is a tl::expected
388 template <class T> struct is_expected_impl : std::false_type {};
389 template <class T, class E>
390 struct is_expected_impl<expected<T, E>> : std::true_type {};
391 template <class T> using is_expected = is_expected_impl<decay_t<T>>;
393 template <class T, class E, class U>
394 using expected_enable_forward_value = detail::enable_if_t<
395 std::is_constructible<T, U &&>::value &&
396 !std::is_same<detail::decay_t<U>, in_place_t>::value &&
397 !std::is_same<expected<T, E>, detail::decay_t<U>>::value &&
398 !std::is_same<unexpected<E>, detail::decay_t<U>>::value>;
400 template <class T, class E, class U, class G, class UR, class GR>
401 using expected_enable_from_other = detail::enable_if_t<
402 std::is_constructible<T, UR>::value &&
403 std::is_constructible<E, GR>::value &&
404 !std::is_constructible<T, expected<U, G> &>::value &&
405 !std::is_constructible<T, expected<U, G> &&>::value &&
406 !std::is_constructible<T, const expected<U, G> &>::value &&
407 !std::is_constructible<T, const expected<U, G> &&>::value &&
408 !std::is_convertible<expected<U, G> &, T>::value &&
409 !std::is_convertible<expected<U, G> &&, T>::value &&
410 !std::is_convertible<const expected<U, G> &, T>::value &&
411 !std::is_convertible<const expected<U, G> &&, T>::value>;
413 template <class T, class U>
414 using is_void_or = conditional_t<std::is_void<T>::value, std::true_type, U>;
416 template <class T>
417 using is_copy_constructible_or_void =
418 is_void_or<T, std::is_copy_constructible<T>>;
420 template <class T>
421 using is_move_constructible_or_void =
422 is_void_or<T, std::is_move_constructible<T>>;
424 template <class T>
425 using is_copy_assignable_or_void = is_void_or<T, std::is_copy_assignable<T>>;
427 template <class T>
428 using is_move_assignable_or_void = is_void_or<T, std::is_move_assignable<T>>;
430 } // namespace detail
432 namespace detail {
433 struct no_init_t {};
434 static constexpr no_init_t no_init{};
436 // Implements the storage of the values, and ensures that the destructor is
437 // trivial if it can be.
439 // This specialization is for where neither `T` or `E` is trivially
440 // destructible, so the destructors must be called on destruction of the
441 // `expected`
442 template <class T, class E, bool = std::is_trivially_destructible<T>::value,
443 bool = std::is_trivially_destructible<E>::value>
444 struct expected_storage_base {
445 constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
446 constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {}
448 template <class... Args,
449 detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
450 nullptr>
451 constexpr expected_storage_base(in_place_t, Args &&...args)
452 : m_val(std::forward<Args>(args)...), m_has_val(true) {}
454 template <class U, class... Args,
455 detail::enable_if_t<std::is_constructible<
456 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
457 constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
458 Args &&...args)
459 : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
460 template <class... Args,
461 detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
462 nullptr>
463 constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
464 : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
466 template <class U, class... Args,
467 detail::enable_if_t<std::is_constructible<
468 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
469 constexpr explicit expected_storage_base(unexpect_t,
470 std::initializer_list<U> il,
471 Args &&...args)
472 : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
474 ~expected_storage_base() {
475 if (m_has_val) {
476 m_val.~T();
477 } else {
478 m_unexpect.~unexpected<E>();
481 union {
482 T m_val;
483 unexpected<E> m_unexpect;
484 char m_no_init;
486 bool m_has_val;
489 // This specialization is for when both `T` and `E` are trivially-destructible,
490 // so the destructor of the `expected` can be trivial.
491 template <class T, class E> struct expected_storage_base<T, E, true, true> {
492 constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
493 constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {}
495 template <class... Args,
496 detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
497 nullptr>
498 constexpr expected_storage_base(in_place_t, Args &&...args)
499 : m_val(std::forward<Args>(args)...), m_has_val(true) {}
501 template <class U, class... Args,
502 detail::enable_if_t<std::is_constructible<
503 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
504 constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
505 Args &&...args)
506 : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
507 template <class... Args,
508 detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
509 nullptr>
510 constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
511 : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
513 template <class U, class... Args,
514 detail::enable_if_t<std::is_constructible<
515 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
516 constexpr explicit expected_storage_base(unexpect_t,
517 std::initializer_list<U> il,
518 Args &&...args)
519 : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
521 ~expected_storage_base() = default;
522 union {
523 T m_val;
524 unexpected<E> m_unexpect;
525 char m_no_init;
527 bool m_has_val;
530 // T is trivial, E is not.
531 template <class T, class E> struct expected_storage_base<T, E, true, false> {
532 constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
533 TL_EXPECTED_MSVC2015_CONSTEXPR expected_storage_base(no_init_t)
534 : m_no_init(), m_has_val(false) {}
536 template <class... Args,
537 detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
538 nullptr>
539 constexpr expected_storage_base(in_place_t, Args &&...args)
540 : m_val(std::forward<Args>(args)...), m_has_val(true) {}
542 template <class U, class... Args,
543 detail::enable_if_t<std::is_constructible<
544 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
545 constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
546 Args &&...args)
547 : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
548 template <class... Args,
549 detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
550 nullptr>
551 constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
552 : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
554 template <class U, class... Args,
555 detail::enable_if_t<std::is_constructible<
556 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
557 constexpr explicit expected_storage_base(unexpect_t,
558 std::initializer_list<U> il,
559 Args &&...args)
560 : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
562 ~expected_storage_base() {
563 if (!m_has_val) {
564 m_unexpect.~unexpected<E>();
568 union {
569 T m_val;
570 unexpected<E> m_unexpect;
571 char m_no_init;
573 bool m_has_val;
576 // E is trivial, T is not.
577 template <class T, class E> struct expected_storage_base<T, E, false, true> {
578 constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
579 constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {}
581 template <class... Args,
582 detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
583 nullptr>
584 constexpr expected_storage_base(in_place_t, Args &&...args)
585 : m_val(std::forward<Args>(args)...), m_has_val(true) {}
587 template <class U, class... Args,
588 detail::enable_if_t<std::is_constructible<
589 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
590 constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
591 Args &&...args)
592 : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
593 template <class... Args,
594 detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
595 nullptr>
596 constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
597 : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
599 template <class U, class... Args,
600 detail::enable_if_t<std::is_constructible<
601 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
602 constexpr explicit expected_storage_base(unexpect_t,
603 std::initializer_list<U> il,
604 Args &&...args)
605 : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
607 ~expected_storage_base() {
608 if (m_has_val) {
609 m_val.~T();
612 union {
613 T m_val;
614 unexpected<E> m_unexpect;
615 char m_no_init;
617 bool m_has_val;
620 // `T` is `void`, `E` is trivially-destructible
621 template <class E> struct expected_storage_base<void, E, false, true> {
622 #if __GNUC__ <= 5
623 //no constexpr for GCC 4/5 bug
624 #else
625 TL_EXPECTED_MSVC2015_CONSTEXPR
626 #endif
627 expected_storage_base() : m_has_val(true) {}
629 constexpr expected_storage_base(no_init_t) : m_val(), m_has_val(false) {}
631 constexpr expected_storage_base(in_place_t) : m_has_val(true) {}
633 template <class... Args,
634 detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
635 nullptr>
636 constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
637 : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
639 template <class U, class... Args,
640 detail::enable_if_t<std::is_constructible<
641 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
642 constexpr explicit expected_storage_base(unexpect_t,
643 std::initializer_list<U> il,
644 Args &&...args)
645 : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
647 ~expected_storage_base() = default;
648 struct dummy {};
649 union {
650 unexpected<E> m_unexpect;
651 dummy m_val;
653 bool m_has_val;
656 // `T` is `void`, `E` is not trivially-destructible
657 template <class E> struct expected_storage_base<void, E, false, false> {
658 constexpr expected_storage_base() : m_dummy(), m_has_val(true) {}
659 constexpr expected_storage_base(no_init_t) : m_dummy(), m_has_val(false) {}
661 constexpr expected_storage_base(in_place_t) : m_dummy(), m_has_val(true) {}
663 template <class... Args,
664 detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
665 nullptr>
666 constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
667 : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
669 template <class U, class... Args,
670 detail::enable_if_t<std::is_constructible<
671 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
672 constexpr explicit expected_storage_base(unexpect_t,
673 std::initializer_list<U> il,
674 Args &&...args)
675 : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
677 ~expected_storage_base() {
678 if (!m_has_val) {
679 m_unexpect.~unexpected<E>();
683 union {
684 unexpected<E> m_unexpect;
685 char m_dummy;
687 bool m_has_val;
690 // This base class provides some handy member functions which can be used in
691 // further derived classes
692 template <class T, class E>
693 struct expected_operations_base : expected_storage_base<T, E> {
694 using expected_storage_base<T, E>::expected_storage_base;
696 template <class... Args> void construct(Args &&...args) noexcept {
697 new (std::addressof(this->m_val)) T(std::forward<Args>(args)...);
698 this->m_has_val = true;
701 template <class Rhs> void construct_with(Rhs &&rhs) noexcept {
702 new (std::addressof(this->m_val)) T(std::forward<Rhs>(rhs).get());
703 this->m_has_val = true;
706 template <class... Args> void construct_error(Args &&...args) noexcept {
707 new (std::addressof(this->m_unexpect))
708 unexpected<E>(std::forward<Args>(args)...);
709 this->m_has_val = false;
712 #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
714 // These assign overloads ensure that the most efficient assignment
715 // implementation is used while maintaining the strong exception guarantee.
716 // The problematic case is where rhs has a value, but *this does not.
718 // This overload handles the case where we can just copy-construct `T`
719 // directly into place without throwing.
720 template <class U = T,
721 detail::enable_if_t<std::is_nothrow_copy_constructible<U>::value>
722 * = nullptr>
723 void assign(const expected_operations_base &rhs) noexcept {
724 if (!this->m_has_val && rhs.m_has_val) {
725 geterr().~unexpected<E>();
726 construct(rhs.get());
727 } else {
728 assign_common(rhs);
732 // This overload handles the case where we can attempt to create a copy of
733 // `T`, then no-throw move it into place if the copy was successful.
734 template <class U = T,
735 detail::enable_if_t<!std::is_nothrow_copy_constructible<U>::value &&
736 std::is_nothrow_move_constructible<U>::value>
737 * = nullptr>
738 void assign(const expected_operations_base &rhs) noexcept {
739 if (!this->m_has_val && rhs.m_has_val) {
740 T tmp = rhs.get();
741 geterr().~unexpected<E>();
742 construct(std::move(tmp));
743 } else {
744 assign_common(rhs);
748 // This overload is the worst-case, where we have to move-construct the
749 // unexpected value into temporary storage, then try to copy the T into place.
750 // If the construction succeeds, then everything is fine, but if it throws,
751 // then we move the old unexpected value back into place before rethrowing the
752 // exception.
753 template <class U = T,
754 detail::enable_if_t<!std::is_nothrow_copy_constructible<U>::value &&
755 !std::is_nothrow_move_constructible<U>::value>
756 * = nullptr>
757 void assign(const expected_operations_base &rhs) {
758 if (!this->m_has_val && rhs.m_has_val) {
759 auto tmp = std::move(geterr());
760 geterr().~unexpected<E>();
762 #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
763 try {
764 construct(rhs.get());
765 } catch (...) {
766 geterr() = std::move(tmp);
767 throw;
769 #else
770 construct(rhs.get());
771 #endif
772 } else {
773 assign_common(rhs);
777 // These overloads do the same as above, but for rvalues
778 template <class U = T,
779 detail::enable_if_t<std::is_nothrow_move_constructible<U>::value>
780 * = nullptr>
781 void assign(expected_operations_base &&rhs) noexcept {
782 if (!this->m_has_val && rhs.m_has_val) {
783 geterr().~unexpected<E>();
784 construct(std::move(rhs).get());
785 } else {
786 assign_common(std::move(rhs));
790 template <class U = T,
791 detail::enable_if_t<!std::is_nothrow_move_constructible<U>::value>
792 * = nullptr>
793 void assign(expected_operations_base &&rhs) {
794 if (!this->m_has_val && rhs.m_has_val) {
795 auto tmp = std::move(geterr());
796 geterr().~unexpected<E>();
797 #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
798 try {
799 construct(std::move(rhs).get());
800 } catch (...) {
801 geterr() = std::move(tmp);
802 throw;
804 #else
805 construct(std::move(rhs).get());
806 #endif
807 } else {
808 assign_common(std::move(rhs));
812 #else
814 // If exceptions are disabled then we can just copy-construct
815 void assign(const expected_operations_base &rhs) noexcept {
816 if (!this->m_has_val && rhs.m_has_val) {
817 geterr().~unexpected<E>();
818 construct(rhs.get());
819 } else {
820 assign_common(rhs);
824 void assign(expected_operations_base &&rhs) noexcept {
825 if (!this->m_has_val && rhs.m_has_val) {
826 geterr().~unexpected<E>();
827 construct(std::move(rhs).get());
828 } else {
829 assign_common(std::move(rhs));
833 #endif
835 // The common part of move/copy assigning
836 template <class Rhs> void assign_common(Rhs &&rhs) {
837 if (this->m_has_val) {
838 if (rhs.m_has_val) {
839 get() = std::forward<Rhs>(rhs).get();
840 } else {
841 destroy_val();
842 construct_error(std::forward<Rhs>(rhs).geterr());
844 } else {
845 if (!rhs.m_has_val) {
846 geterr() = std::forward<Rhs>(rhs).geterr();
851 bool has_value() const { return this->m_has_val; }
853 TL_EXPECTED_11_CONSTEXPR T &get() & { return this->m_val; }
854 constexpr const T &get() const & { return this->m_val; }
855 TL_EXPECTED_11_CONSTEXPR T &&get() && { return std::move(this->m_val); }
856 #ifndef TL_EXPECTED_NO_CONSTRR
857 constexpr const T &&get() const && { return std::move(this->m_val); }
858 #endif
860 TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() & {
861 return this->m_unexpect;
863 constexpr const unexpected<E> &geterr() const & { return this->m_unexpect; }
864 TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() && {
865 return std::move(this->m_unexpect);
867 #ifndef TL_EXPECTED_NO_CONSTRR
868 constexpr const unexpected<E> &&geterr() const && {
869 return std::move(this->m_unexpect);
871 #endif
873 TL_EXPECTED_11_CONSTEXPR void destroy_val() { get().~T(); }
876 // This base class provides some handy member functions which can be used in
877 // further derived classes
878 template <class E>
879 struct expected_operations_base<void, E> : expected_storage_base<void, E> {
880 using expected_storage_base<void, E>::expected_storage_base;
882 template <class... Args> void construct() noexcept { this->m_has_val = true; }
884 // This function doesn't use its argument, but needs it so that code in
885 // levels above this can work independently of whether T is void
886 template <class Rhs> void construct_with(Rhs &&) noexcept {
887 this->m_has_val = true;
890 template <class... Args> void construct_error(Args &&...args) noexcept {
891 new (std::addressof(this->m_unexpect))
892 unexpected<E>(std::forward<Args>(args)...);
893 this->m_has_val = false;
896 template <class Rhs> void assign(Rhs &&rhs) noexcept {
897 if (!this->m_has_val) {
898 if (rhs.m_has_val) {
899 geterr().~unexpected<E>();
900 construct();
901 } else {
902 geterr() = std::forward<Rhs>(rhs).geterr();
904 } else {
905 if (!rhs.m_has_val) {
906 construct_error(std::forward<Rhs>(rhs).geterr());
911 bool has_value() const { return this->m_has_val; }
913 TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() & {
914 return this->m_unexpect;
916 constexpr const unexpected<E> &geterr() const & { return this->m_unexpect; }
917 TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() && {
918 return std::move(this->m_unexpect);
920 #ifndef TL_EXPECTED_NO_CONSTRR
921 constexpr const unexpected<E> &&geterr() const && {
922 return std::move(this->m_unexpect);
924 #endif
926 TL_EXPECTED_11_CONSTEXPR void destroy_val() {
927 // no-op
931 // This class manages conditionally having a trivial copy constructor
932 // This specialization is for when T and E are trivially copy constructible
933 template <class T, class E,
934 bool = is_void_or<T, TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T)>::
935 value &&TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value>
936 struct expected_copy_base : expected_operations_base<T, E> {
937 using expected_operations_base<T, E>::expected_operations_base;
940 // This specialization is for when T or E are not trivially copy constructible
941 template <class T, class E>
942 struct expected_copy_base<T, E, false> : expected_operations_base<T, E> {
943 using expected_operations_base<T, E>::expected_operations_base;
945 expected_copy_base() = default;
946 expected_copy_base(const expected_copy_base &rhs)
947 : expected_operations_base<T, E>(no_init) {
948 if (rhs.has_value()) {
949 this->construct_with(rhs);
950 } else {
951 this->construct_error(rhs.geterr());
955 expected_copy_base(expected_copy_base &&rhs) = default;
956 expected_copy_base &operator=(const expected_copy_base &rhs) = default;
957 expected_copy_base &operator=(expected_copy_base &&rhs) = default;
960 // This class manages conditionally having a trivial move constructor
961 // Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it
962 // doesn't implement an analogue to std::is_trivially_move_constructible. We
963 // have to make do with a non-trivial move constructor even if T is trivially
964 // move constructible
965 #ifndef TL_EXPECTED_GCC49
966 template <class T, class E,
967 bool = is_void_or<T, std::is_trivially_move_constructible<T>>::value
968 &&std::is_trivially_move_constructible<E>::value>
969 struct expected_move_base : expected_copy_base<T, E> {
970 using expected_copy_base<T, E>::expected_copy_base;
972 #else
973 template <class T, class E, bool = false> struct expected_move_base;
974 #endif
975 template <class T, class E>
976 struct expected_move_base<T, E, false> : expected_copy_base<T, E> {
977 using expected_copy_base<T, E>::expected_copy_base;
979 expected_move_base() = default;
980 expected_move_base(const expected_move_base &rhs) = default;
982 expected_move_base(expected_move_base &&rhs) noexcept(
983 std::is_nothrow_move_constructible<T>::value)
984 : expected_copy_base<T, E>(no_init) {
985 if (rhs.has_value()) {
986 this->construct_with(std::move(rhs));
987 } else {
988 this->construct_error(std::move(rhs.geterr()));
991 expected_move_base &operator=(const expected_move_base &rhs) = default;
992 expected_move_base &operator=(expected_move_base &&rhs) = default;
995 // This class manages conditionally having a trivial copy assignment operator
996 template <class T, class E,
997 bool = is_void_or<
998 T, conjunction<TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T),
999 TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T),
1000 TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T)>>::value
1001 &&TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(E)::value
1002 &&TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value
1003 &&TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(E)::value>
1004 struct expected_copy_assign_base : expected_move_base<T, E> {
1005 using expected_move_base<T, E>::expected_move_base;
1008 template <class T, class E>
1009 struct expected_copy_assign_base<T, E, false> : expected_move_base<T, E> {
1010 using expected_move_base<T, E>::expected_move_base;
1012 expected_copy_assign_base() = default;
1013 expected_copy_assign_base(const expected_copy_assign_base &rhs) = default;
1015 expected_copy_assign_base(expected_copy_assign_base &&rhs) = default;
1016 expected_copy_assign_base &operator=(const expected_copy_assign_base &rhs) {
1017 this->assign(rhs);
1018 return *this;
1020 expected_copy_assign_base &
1021 operator=(expected_copy_assign_base &&rhs) = default;
1024 // This class manages conditionally having a trivial move assignment operator
1025 // Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it
1026 // doesn't implement an analogue to std::is_trivially_move_assignable. We have
1027 // to make do with a non-trivial move assignment operator even if T is trivially
1028 // move assignable
1029 #ifndef TL_EXPECTED_GCC49
1030 template <class T, class E,
1031 bool =
1032 is_void_or<T, conjunction<std::is_trivially_destructible<T>,
1033 std::is_trivially_move_constructible<T>,
1034 std::is_trivially_move_assignable<T>>>::
1035 value &&std::is_trivially_destructible<E>::value
1036 &&std::is_trivially_move_constructible<E>::value
1037 &&std::is_trivially_move_assignable<E>::value>
1038 struct expected_move_assign_base : expected_copy_assign_base<T, E> {
1039 using expected_copy_assign_base<T, E>::expected_copy_assign_base;
1041 #else
1042 template <class T, class E, bool = false> struct expected_move_assign_base;
1043 #endif
1045 template <class T, class E>
1046 struct expected_move_assign_base<T, E, false>
1047 : expected_copy_assign_base<T, E> {
1048 using expected_copy_assign_base<T, E>::expected_copy_assign_base;
1050 expected_move_assign_base() = default;
1051 expected_move_assign_base(const expected_move_assign_base &rhs) = default;
1053 expected_move_assign_base(expected_move_assign_base &&rhs) = default;
1055 expected_move_assign_base &
1056 operator=(const expected_move_assign_base &rhs) = default;
1058 expected_move_assign_base &
1059 operator=(expected_move_assign_base &&rhs) noexcept(
1060 std::is_nothrow_move_constructible<T>::value
1061 &&std::is_nothrow_move_assignable<T>::value) {
1062 this->assign(std::move(rhs));
1063 return *this;
1067 // expected_delete_ctor_base will conditionally delete copy and move
1068 // constructors depending on whether T is copy/move constructible
1069 template <class T, class E,
1070 bool EnableCopy = (is_copy_constructible_or_void<T>::value &&
1071 std::is_copy_constructible<E>::value),
1072 bool EnableMove = (is_move_constructible_or_void<T>::value &&
1073 std::is_move_constructible<E>::value)>
1074 struct expected_delete_ctor_base {
1075 expected_delete_ctor_base() = default;
1076 expected_delete_ctor_base(const expected_delete_ctor_base &) = default;
1077 expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = default;
1078 expected_delete_ctor_base &
1079 operator=(const expected_delete_ctor_base &) = default;
1080 expected_delete_ctor_base &
1081 operator=(expected_delete_ctor_base &&) noexcept = default;
1084 template <class T, class E>
1085 struct expected_delete_ctor_base<T, E, true, false> {
1086 expected_delete_ctor_base() = default;
1087 expected_delete_ctor_base(const expected_delete_ctor_base &) = default;
1088 expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = delete;
1089 expected_delete_ctor_base &
1090 operator=(const expected_delete_ctor_base &) = default;
1091 expected_delete_ctor_base &
1092 operator=(expected_delete_ctor_base &&) noexcept = default;
1095 template <class T, class E>
1096 struct expected_delete_ctor_base<T, E, false, true> {
1097 expected_delete_ctor_base() = default;
1098 expected_delete_ctor_base(const expected_delete_ctor_base &) = delete;
1099 expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = default;
1100 expected_delete_ctor_base &
1101 operator=(const expected_delete_ctor_base &) = default;
1102 expected_delete_ctor_base &
1103 operator=(expected_delete_ctor_base &&) noexcept = default;
1106 template <class T, class E>
1107 struct expected_delete_ctor_base<T, E, false, false> {
1108 expected_delete_ctor_base() = default;
1109 expected_delete_ctor_base(const expected_delete_ctor_base &) = delete;
1110 expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = delete;
1111 expected_delete_ctor_base &
1112 operator=(const expected_delete_ctor_base &) = default;
1113 expected_delete_ctor_base &
1114 operator=(expected_delete_ctor_base &&) noexcept = default;
1117 // expected_delete_assign_base will conditionally delete copy and move
1118 // constructors depending on whether T and E are copy/move constructible +
1119 // assignable
1120 template <class T, class E,
1121 bool EnableCopy = (is_copy_constructible_or_void<T>::value &&
1122 std::is_copy_constructible<E>::value &&
1123 is_copy_assignable_or_void<T>::value &&
1124 std::is_copy_assignable<E>::value),
1125 bool EnableMove = (is_move_constructible_or_void<T>::value &&
1126 std::is_move_constructible<E>::value &&
1127 is_move_assignable_or_void<T>::value &&
1128 std::is_move_assignable<E>::value)>
1129 struct expected_delete_assign_base {
1130 expected_delete_assign_base() = default;
1131 expected_delete_assign_base(const expected_delete_assign_base &) = default;
1132 expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
1133 default;
1134 expected_delete_assign_base &
1135 operator=(const expected_delete_assign_base &) = default;
1136 expected_delete_assign_base &
1137 operator=(expected_delete_assign_base &&) noexcept = default;
1140 template <class T, class E>
1141 struct expected_delete_assign_base<T, E, true, false> {
1142 expected_delete_assign_base() = default;
1143 expected_delete_assign_base(const expected_delete_assign_base &) = default;
1144 expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
1145 default;
1146 expected_delete_assign_base &
1147 operator=(const expected_delete_assign_base &) = default;
1148 expected_delete_assign_base &
1149 operator=(expected_delete_assign_base &&) noexcept = delete;
1152 template <class T, class E>
1153 struct expected_delete_assign_base<T, E, false, true> {
1154 expected_delete_assign_base() = default;
1155 expected_delete_assign_base(const expected_delete_assign_base &) = default;
1156 expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
1157 default;
1158 expected_delete_assign_base &
1159 operator=(const expected_delete_assign_base &) = delete;
1160 expected_delete_assign_base &
1161 operator=(expected_delete_assign_base &&) noexcept = default;
1164 template <class T, class E>
1165 struct expected_delete_assign_base<T, E, false, false> {
1166 expected_delete_assign_base() = default;
1167 expected_delete_assign_base(const expected_delete_assign_base &) = default;
1168 expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
1169 default;
1170 expected_delete_assign_base &
1171 operator=(const expected_delete_assign_base &) = delete;
1172 expected_delete_assign_base &
1173 operator=(expected_delete_assign_base &&) noexcept = delete;
1176 // This is needed to be able to construct the expected_default_ctor_base which
1177 // follows, while still conditionally deleting the default constructor.
1178 struct default_constructor_tag {
1179 explicit constexpr default_constructor_tag() = default;
1182 // expected_default_ctor_base will ensure that expected has a deleted default
1183 // consturctor if T is not default constructible.
1184 // This specialization is for when T is default constructible
1185 template <class T, class E,
1186 bool Enable =
1187 std::is_default_constructible<T>::value || std::is_void<T>::value>
1188 struct expected_default_ctor_base {
1189 constexpr expected_default_ctor_base() noexcept = default;
1190 constexpr expected_default_ctor_base(
1191 expected_default_ctor_base const &) noexcept = default;
1192 constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept =
1193 default;
1194 expected_default_ctor_base &
1195 operator=(expected_default_ctor_base const &) noexcept = default;
1196 expected_default_ctor_base &
1197 operator=(expected_default_ctor_base &&) noexcept = default;
1199 constexpr explicit expected_default_ctor_base(default_constructor_tag) {}
1202 // This specialization is for when T is not default constructible
1203 template <class T, class E> struct expected_default_ctor_base<T, E, false> {
1204 constexpr expected_default_ctor_base() noexcept = delete;
1205 constexpr expected_default_ctor_base(
1206 expected_default_ctor_base const &) noexcept = default;
1207 constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept =
1208 default;
1209 expected_default_ctor_base &
1210 operator=(expected_default_ctor_base const &) noexcept = default;
1211 expected_default_ctor_base &
1212 operator=(expected_default_ctor_base &&) noexcept = default;
1214 constexpr explicit expected_default_ctor_base(default_constructor_tag) {}
1216 } // namespace detail
1218 template <class E> class bad_expected_access : public std::exception {
1219 public:
1220 explicit bad_expected_access(E e) : m_val(std::move(e)) {}
1222 virtual const char *what() const noexcept override {
1223 return "Bad expected access";
1226 const E &error() const & { return m_val; }
1227 E &error() & { return m_val; }
1228 const E &&error() const && { return std::move(m_val); }
1229 E &&error() && { return std::move(m_val); }
1231 private:
1232 E m_val;
1235 /// An `expected<T, E>` object is an object that contains the storage for
1236 /// another object and manages the lifetime of this contained object `T`.
1237 /// Alternatively it could contain the storage for another unexpected object
1238 /// `E`. The contained object may not be initialized after the expected object
1239 /// has been initialized, and may not be destroyed before the expected object
1240 /// has been destroyed. The initialization state of the contained object is
1241 /// tracked by the expected object.
1242 template <class T, class E>
1243 class expected : private detail::expected_move_assign_base<T, E>,
1244 private detail::expected_delete_ctor_base<T, E>,
1245 private detail::expected_delete_assign_base<T, E>,
1246 private detail::expected_default_ctor_base<T, E> {
1247 static_assert(!std::is_reference<T>::value, "T must not be a reference");
1248 static_assert(!std::is_same<T, std::remove_cv<in_place_t>::type>::value,
1249 "T must not be in_place_t");
1250 static_assert(!std::is_same<T, std::remove_cv<unexpect_t>::type>::value,
1251 "T must not be unexpect_t");
1252 static_assert(
1253 !std::is_same<T, typename std::remove_cv<unexpected<E>>::type>::value,
1254 "T must not be unexpected<E>");
1255 static_assert(!std::is_reference<E>::value, "E must not be a reference");
1257 T *valptr() { return std::addressof(this->m_val); }
1258 const T *valptr() const { return std::addressof(this->m_val); }
1259 unexpected<E> *errptr() { return std::addressof(this->m_unexpect); }
1260 const unexpected<E> *errptr() const {
1261 return std::addressof(this->m_unexpect);
1264 template <class U = T,
1265 detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
1266 TL_EXPECTED_11_CONSTEXPR U &val() {
1267 return this->m_val;
1269 TL_EXPECTED_11_CONSTEXPR unexpected<E> &err() { return this->m_unexpect; }
1271 template <class U = T,
1272 detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
1273 constexpr const U &val() const {
1274 return this->m_val;
1276 constexpr const unexpected<E> &err() const { return this->m_unexpect; }
1278 using impl_base = detail::expected_move_assign_base<T, E>;
1279 using ctor_base = detail::expected_default_ctor_base<T, E>;
1281 public:
1282 typedef T value_type;
1283 typedef E error_type;
1284 typedef unexpected<E> unexpected_type;
1286 #if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
1287 !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
1288 template <class F> TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) & {
1289 return and_then_impl(*this, std::forward<F>(f));
1291 template <class F> TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) && {
1292 return and_then_impl(std::move(*this), std::forward<F>(f));
1294 template <class F> constexpr auto and_then(F &&f) const & {
1295 return and_then_impl(*this, std::forward<F>(f));
1298 #ifndef TL_EXPECTED_NO_CONSTRR
1299 template <class F> constexpr auto and_then(F &&f) const && {
1300 return and_then_impl(std::move(*this), std::forward<F>(f));
1302 #endif
1304 #else
1305 template <class F>
1306 TL_EXPECTED_11_CONSTEXPR auto
1307 and_then(F &&f) & -> decltype(and_then_impl(std::declval<expected &>(),
1308 std::forward<F>(f))) {
1309 return and_then_impl(*this, std::forward<F>(f));
1311 template <class F>
1312 TL_EXPECTED_11_CONSTEXPR auto
1313 and_then(F &&f) && -> decltype(and_then_impl(std::declval<expected &&>(),
1314 std::forward<F>(f))) {
1315 return and_then_impl(std::move(*this), std::forward<F>(f));
1317 template <class F>
1318 constexpr auto and_then(F &&f) const & -> decltype(and_then_impl(
1319 std::declval<expected const &>(), std::forward<F>(f))) {
1320 return and_then_impl(*this, std::forward<F>(f));
1323 #ifndef TL_EXPECTED_NO_CONSTRR
1324 template <class F>
1325 constexpr auto and_then(F &&f) const && -> decltype(and_then_impl(
1326 std::declval<expected const &&>(), std::forward<F>(f))) {
1327 return and_then_impl(std::move(*this), std::forward<F>(f));
1329 #endif
1330 #endif
1332 #if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
1333 !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
1334 template <class F> TL_EXPECTED_11_CONSTEXPR auto map(F &&f) & {
1335 return expected_map_impl(*this, std::forward<F>(f));
1337 template <class F> TL_EXPECTED_11_CONSTEXPR auto map(F &&f) && {
1338 return expected_map_impl(std::move(*this), std::forward<F>(f));
1340 template <class F> constexpr auto map(F &&f) const & {
1341 return expected_map_impl(*this, std::forward<F>(f));
1343 template <class F> constexpr auto map(F &&f) const && {
1344 return expected_map_impl(std::move(*this), std::forward<F>(f));
1346 #else
1347 template <class F>
1348 TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(
1349 std::declval<expected &>(), std::declval<F &&>()))
1350 map(F &&f) & {
1351 return expected_map_impl(*this, std::forward<F>(f));
1353 template <class F>
1354 TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval<expected>(),
1355 std::declval<F &&>()))
1356 map(F &&f) && {
1357 return expected_map_impl(std::move(*this), std::forward<F>(f));
1359 template <class F>
1360 constexpr decltype(expected_map_impl(std::declval<const expected &>(),
1361 std::declval<F &&>()))
1362 map(F &&f) const & {
1363 return expected_map_impl(*this, std::forward<F>(f));
1366 #ifndef TL_EXPECTED_NO_CONSTRR
1367 template <class F>
1368 constexpr decltype(expected_map_impl(std::declval<const expected &&>(),
1369 std::declval<F &&>()))
1370 map(F &&f) const && {
1371 return expected_map_impl(std::move(*this), std::forward<F>(f));
1373 #endif
1374 #endif
1376 #if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
1377 !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
1378 template <class F> TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) & {
1379 return expected_map_impl(*this, std::forward<F>(f));
1381 template <class F> TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) && {
1382 return expected_map_impl(std::move(*this), std::forward<F>(f));
1384 template <class F> constexpr auto transform(F &&f) const & {
1385 return expected_map_impl(*this, std::forward<F>(f));
1387 template <class F> constexpr auto transform(F &&f) const && {
1388 return expected_map_impl(std::move(*this), std::forward<F>(f));
1390 #else
1391 template <class F>
1392 TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(
1393 std::declval<expected &>(), std::declval<F &&>()))
1394 transform(F &&f) & {
1395 return expected_map_impl(*this, std::forward<F>(f));
1397 template <class F>
1398 TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval<expected>(),
1399 std::declval<F &&>()))
1400 transform(F &&f) && {
1401 return expected_map_impl(std::move(*this), std::forward<F>(f));
1403 template <class F>
1404 constexpr decltype(expected_map_impl(std::declval<const expected &>(),
1405 std::declval<F &&>()))
1406 transform(F &&f) const & {
1407 return expected_map_impl(*this, std::forward<F>(f));
1410 #ifndef TL_EXPECTED_NO_CONSTRR
1411 template <class F>
1412 constexpr decltype(expected_map_impl(std::declval<const expected &&>(),
1413 std::declval<F &&>()))
1414 transform(F &&f) const && {
1415 return expected_map_impl(std::move(*this), std::forward<F>(f));
1417 #endif
1418 #endif
1420 #if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
1421 !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
1422 template <class F> TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) & {
1423 return map_error_impl(*this, std::forward<F>(f));
1425 template <class F> TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) && {
1426 return map_error_impl(std::move(*this), std::forward<F>(f));
1428 template <class F> constexpr auto map_error(F &&f) const & {
1429 return map_error_impl(*this, std::forward<F>(f));
1431 template <class F> constexpr auto map_error(F &&f) const && {
1432 return map_error_impl(std::move(*this), std::forward<F>(f));
1434 #else
1435 template <class F>
1436 TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &>(),
1437 std::declval<F &&>()))
1438 map_error(F &&f) & {
1439 return map_error_impl(*this, std::forward<F>(f));
1441 template <class F>
1442 TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &&>(),
1443 std::declval<F &&>()))
1444 map_error(F &&f) && {
1445 return map_error_impl(std::move(*this), std::forward<F>(f));
1447 template <class F>
1448 constexpr decltype(map_error_impl(std::declval<const expected &>(),
1449 std::declval<F &&>()))
1450 map_error(F &&f) const & {
1451 return map_error_impl(*this, std::forward<F>(f));
1454 #ifndef TL_EXPECTED_NO_CONSTRR
1455 template <class F>
1456 constexpr decltype(map_error_impl(std::declval<const expected &&>(),
1457 std::declval<F &&>()))
1458 map_error(F &&f) const && {
1459 return map_error_impl(std::move(*this), std::forward<F>(f));
1461 #endif
1462 #endif
1463 #if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
1464 !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
1465 template <class F> TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) & {
1466 return map_error_impl(*this, std::forward<F>(f));
1468 template <class F> TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) && {
1469 return map_error_impl(std::move(*this), std::forward<F>(f));
1471 template <class F> constexpr auto transform_error(F &&f) const & {
1472 return map_error_impl(*this, std::forward<F>(f));
1474 template <class F> constexpr auto transform_error(F &&f) const && {
1475 return map_error_impl(std::move(*this), std::forward<F>(f));
1477 #else
1478 template <class F>
1479 TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &>(),
1480 std::declval<F &&>()))
1481 transform_error(F &&f) & {
1482 return map_error_impl(*this, std::forward<F>(f));
1484 template <class F>
1485 TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &&>(),
1486 std::declval<F &&>()))
1487 transform_error(F &&f) && {
1488 return map_error_impl(std::move(*this), std::forward<F>(f));
1490 template <class F>
1491 constexpr decltype(map_error_impl(std::declval<const expected &>(),
1492 std::declval<F &&>()))
1493 transform_error(F &&f) const & {
1494 return map_error_impl(*this, std::forward<F>(f));
1497 #ifndef TL_EXPECTED_NO_CONSTRR
1498 template <class F>
1499 constexpr decltype(map_error_impl(std::declval<const expected &&>(),
1500 std::declval<F &&>()))
1501 transform_error(F &&f) const && {
1502 return map_error_impl(std::move(*this), std::forward<F>(f));
1504 #endif
1505 #endif
1506 template <class F> expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) & {
1507 return or_else_impl(*this, std::forward<F>(f));
1510 template <class F> expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) && {
1511 return or_else_impl(std::move(*this), std::forward<F>(f));
1514 template <class F> expected constexpr or_else(F &&f) const & {
1515 return or_else_impl(*this, std::forward<F>(f));
1518 #ifndef TL_EXPECTED_NO_CONSTRR
1519 template <class F> expected constexpr or_else(F &&f) const && {
1520 return or_else_impl(std::move(*this), std::forward<F>(f));
1522 #endif
1523 constexpr expected() = default;
1524 constexpr expected(const expected &rhs) = default;
1525 constexpr expected(expected &&rhs) = default;
1526 expected &operator=(const expected &rhs) = default;
1527 expected &operator=(expected &&rhs) = default;
1529 template <class... Args,
1530 detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
1531 nullptr>
1532 constexpr expected(in_place_t, Args &&...args)
1533 : impl_base(in_place, std::forward<Args>(args)...),
1534 ctor_base(detail::default_constructor_tag{}) {}
1536 template <class U, class... Args,
1537 detail::enable_if_t<std::is_constructible<
1538 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
1539 constexpr expected(in_place_t, std::initializer_list<U> il, Args &&...args)
1540 : impl_base(in_place, il, std::forward<Args>(args)...),
1541 ctor_base(detail::default_constructor_tag{}) {}
1543 template <class G = E,
1544 detail::enable_if_t<std::is_constructible<E, const G &>::value> * =
1545 nullptr,
1546 detail::enable_if_t<!std::is_convertible<const G &, E>::value> * =
1547 nullptr>
1548 explicit constexpr expected(const unexpected<G> &e)
1549 : impl_base(unexpect, e.value()),
1550 ctor_base(detail::default_constructor_tag{}) {}
1552 template <
1553 class G = E,
1554 detail::enable_if_t<std::is_constructible<E, const G &>::value> * =
1555 nullptr,
1556 detail::enable_if_t<std::is_convertible<const G &, E>::value> * = nullptr>
1557 constexpr expected(unexpected<G> const &e)
1558 : impl_base(unexpect, e.value()),
1559 ctor_base(detail::default_constructor_tag{}) {}
1561 template <
1562 class G = E,
1563 detail::enable_if_t<std::is_constructible<E, G &&>::value> * = nullptr,
1564 detail::enable_if_t<!std::is_convertible<G &&, E>::value> * = nullptr>
1565 explicit constexpr expected(unexpected<G> &&e) noexcept(
1566 std::is_nothrow_constructible<E, G &&>::value)
1567 : impl_base(unexpect, std::move(e.value())),
1568 ctor_base(detail::default_constructor_tag{}) {}
1570 template <
1571 class G = E,
1572 detail::enable_if_t<std::is_constructible<E, G &&>::value> * = nullptr,
1573 detail::enable_if_t<std::is_convertible<G &&, E>::value> * = nullptr>
1574 constexpr expected(unexpected<G> &&e) noexcept(
1575 std::is_nothrow_constructible<E, G &&>::value)
1576 : impl_base(unexpect, std::move(e.value())),
1577 ctor_base(detail::default_constructor_tag{}) {}
1579 template <class... Args,
1580 detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
1581 nullptr>
1582 constexpr explicit expected(unexpect_t, Args &&...args)
1583 : impl_base(unexpect, std::forward<Args>(args)...),
1584 ctor_base(detail::default_constructor_tag{}) {}
1586 template <class U, class... Args,
1587 detail::enable_if_t<std::is_constructible<
1588 E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
1589 constexpr explicit expected(unexpect_t, std::initializer_list<U> il,
1590 Args &&...args)
1591 : impl_base(unexpect, il, std::forward<Args>(args)...),
1592 ctor_base(detail::default_constructor_tag{}) {}
1594 template <class U, class G,
1595 detail::enable_if_t<!(std::is_convertible<U const &, T>::value &&
1596 std::is_convertible<G const &, E>::value)> * =
1597 nullptr,
1598 detail::expected_enable_from_other<T, E, U, G, const U &, const G &>
1599 * = nullptr>
1600 explicit TL_EXPECTED_11_CONSTEXPR expected(const expected<U, G> &rhs)
1601 : ctor_base(detail::default_constructor_tag{}) {
1602 if (rhs.has_value()) {
1603 this->construct(*rhs);
1604 } else {
1605 this->construct_error(rhs.error());
1609 template <class U, class G,
1610 detail::enable_if_t<(std::is_convertible<U const &, T>::value &&
1611 std::is_convertible<G const &, E>::value)> * =
1612 nullptr,
1613 detail::expected_enable_from_other<T, E, U, G, const U &, const G &>
1614 * = nullptr>
1615 TL_EXPECTED_11_CONSTEXPR expected(const expected<U, G> &rhs)
1616 : ctor_base(detail::default_constructor_tag{}) {
1617 if (rhs.has_value()) {
1618 this->construct(*rhs);
1619 } else {
1620 this->construct_error(rhs.error());
1624 template <
1625 class U, class G,
1626 detail::enable_if_t<!(std::is_convertible<U &&, T>::value &&
1627 std::is_convertible<G &&, E>::value)> * = nullptr,
1628 detail::expected_enable_from_other<T, E, U, G, U &&, G &&> * = nullptr>
1629 explicit TL_EXPECTED_11_CONSTEXPR expected(expected<U, G> &&rhs)
1630 : ctor_base(detail::default_constructor_tag{}) {
1631 if (rhs.has_value()) {
1632 this->construct(std::move(*rhs));
1633 } else {
1634 this->construct_error(std::move(rhs.error()));
1638 template <
1639 class U, class G,
1640 detail::enable_if_t<(std::is_convertible<U &&, T>::value &&
1641 std::is_convertible<G &&, E>::value)> * = nullptr,
1642 detail::expected_enable_from_other<T, E, U, G, U &&, G &&> * = nullptr>
1643 TL_EXPECTED_11_CONSTEXPR expected(expected<U, G> &&rhs)
1644 : ctor_base(detail::default_constructor_tag{}) {
1645 if (rhs.has_value()) {
1646 this->construct(std::move(*rhs));
1647 } else {
1648 this->construct_error(std::move(rhs.error()));
1652 template <
1653 class U = T,
1654 detail::enable_if_t<!std::is_convertible<U &&, T>::value> * = nullptr,
1655 detail::expected_enable_forward_value<T, E, U> * = nullptr>
1656 explicit TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v)
1657 : expected(in_place, std::forward<U>(v)) {}
1659 template <
1660 class U = T,
1661 detail::enable_if_t<std::is_convertible<U &&, T>::value> * = nullptr,
1662 detail::expected_enable_forward_value<T, E, U> * = nullptr>
1663 TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v)
1664 : expected(in_place, std::forward<U>(v)) {}
1666 template <
1667 class U = T, class G = T,
1668 detail::enable_if_t<std::is_nothrow_constructible<T, U &&>::value> * =
1669 nullptr,
1670 detail::enable_if_t<!std::is_void<G>::value> * = nullptr,
1671 detail::enable_if_t<
1672 (!std::is_same<expected<T, E>, detail::decay_t<U>>::value &&
1673 !detail::conjunction<std::is_scalar<T>,
1674 std::is_same<T, detail::decay_t<U>>>::value &&
1675 std::is_constructible<T, U>::value &&
1676 std::is_assignable<G &, U>::value &&
1677 std::is_nothrow_move_constructible<E>::value)> * = nullptr>
1678 expected &operator=(U &&v) {
1679 if (has_value()) {
1680 val() = std::forward<U>(v);
1681 } else {
1682 err().~unexpected<E>();
1683 ::new (valptr()) T(std::forward<U>(v));
1684 this->m_has_val = true;
1687 return *this;
1690 template <
1691 class U = T, class G = T,
1692 detail::enable_if_t<!std::is_nothrow_constructible<T, U &&>::value> * =
1693 nullptr,
1694 detail::enable_if_t<!std::is_void<U>::value> * = nullptr,
1695 detail::enable_if_t<
1696 (!std::is_same<expected<T, E>, detail::decay_t<U>>::value &&
1697 !detail::conjunction<std::is_scalar<T>,
1698 std::is_same<T, detail::decay_t<U>>>::value &&
1699 std::is_constructible<T, U>::value &&
1700 std::is_assignable<G &, U>::value &&
1701 std::is_nothrow_move_constructible<E>::value)> * = nullptr>
1702 expected &operator=(U &&v) {
1703 if (has_value()) {
1704 val() = std::forward<U>(v);
1705 } else {
1706 auto tmp = std::move(err());
1707 err().~unexpected<E>();
1709 #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
1710 try {
1711 ::new (valptr()) T(std::forward<U>(v));
1712 this->m_has_val = true;
1713 } catch (...) {
1714 err() = std::move(tmp);
1715 throw;
1717 #else
1718 ::new (valptr()) T(std::forward<U>(v));
1719 this->m_has_val = true;
1720 #endif
1723 return *this;
1726 template <class G = E,
1727 detail::enable_if_t<std::is_nothrow_copy_constructible<G>::value &&
1728 std::is_assignable<G &, G>::value> * = nullptr>
1729 expected &operator=(const unexpected<G> &rhs) {
1730 if (!has_value()) {
1731 err() = rhs;
1732 } else {
1733 this->destroy_val();
1734 ::new (errptr()) unexpected<E>(rhs);
1735 this->m_has_val = false;
1738 return *this;
1741 template <class G = E,
1742 detail::enable_if_t<std::is_nothrow_move_constructible<G>::value &&
1743 std::is_move_assignable<G>::value> * = nullptr>
1744 expected &operator=(unexpected<G> &&rhs) noexcept {
1745 if (!has_value()) {
1746 err() = std::move(rhs);
1747 } else {
1748 this->destroy_val();
1749 ::new (errptr()) unexpected<E>(std::move(rhs));
1750 this->m_has_val = false;
1753 return *this;
1756 template <class... Args, detail::enable_if_t<std::is_nothrow_constructible<
1757 T, Args &&...>::value> * = nullptr>
1758 void emplace(Args &&...args) {
1759 if (has_value()) {
1760 val().~T();
1761 } else {
1762 err().~unexpected<E>();
1763 this->m_has_val = true;
1765 ::new (valptr()) T(std::forward<Args>(args)...);
1768 template <class... Args, detail::enable_if_t<!std::is_nothrow_constructible<
1769 T, Args &&...>::value> * = nullptr>
1770 void emplace(Args &&...args) {
1771 if (has_value()) {
1772 val().~T();
1773 ::new (valptr()) T(std::forward<Args>(args)...);
1774 } else {
1775 auto tmp = std::move(err());
1776 err().~unexpected<E>();
1778 #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
1779 try {
1780 ::new (valptr()) T(std::forward<Args>(args)...);
1781 this->m_has_val = true;
1782 } catch (...) {
1783 err() = std::move(tmp);
1784 throw;
1786 #else
1787 ::new (valptr()) T(std::forward<Args>(args)...);
1788 this->m_has_val = true;
1789 #endif
1793 template <class U, class... Args,
1794 detail::enable_if_t<std::is_nothrow_constructible<
1795 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
1796 void emplace(std::initializer_list<U> il, Args &&...args) {
1797 if (has_value()) {
1798 T t(il, std::forward<Args>(args)...);
1799 val() = std::move(t);
1800 } else {
1801 err().~unexpected<E>();
1802 ::new (valptr()) T(il, std::forward<Args>(args)...);
1803 this->m_has_val = true;
1807 template <class U, class... Args,
1808 detail::enable_if_t<!std::is_nothrow_constructible<
1809 T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
1810 void emplace(std::initializer_list<U> il, Args &&...args) {
1811 if (has_value()) {
1812 T t(il, std::forward<Args>(args)...);
1813 val() = std::move(t);
1814 } else {
1815 auto tmp = std::move(err());
1816 err().~unexpected<E>();
1818 #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
1819 try {
1820 ::new (valptr()) T(il, std::forward<Args>(args)...);
1821 this->m_has_val = true;
1822 } catch (...) {
1823 err() = std::move(tmp);
1824 throw;
1826 #else
1827 ::new (valptr()) T(il, std::forward<Args>(args)...);
1828 this->m_has_val = true;
1829 #endif
1833 private:
1834 using t_is_void = std::true_type;
1835 using t_is_not_void = std::false_type;
1836 using t_is_nothrow_move_constructible = std::true_type;
1837 using move_constructing_t_can_throw = std::false_type;
1838 using e_is_nothrow_move_constructible = std::true_type;
1839 using move_constructing_e_can_throw = std::false_type;
1841 void swap_where_both_have_value(expected & /*rhs*/, t_is_void) noexcept {
1842 // swapping void is a no-op
1845 void swap_where_both_have_value(expected &rhs, t_is_not_void) {
1846 using std::swap;
1847 swap(val(), rhs.val());
1850 void swap_where_only_one_has_value(expected &rhs, t_is_void) noexcept(
1851 std::is_nothrow_move_constructible<E>::value) {
1852 ::new (errptr()) unexpected_type(std::move(rhs.err()));
1853 rhs.err().~unexpected_type();
1854 std::swap(this->m_has_val, rhs.m_has_val);
1857 void swap_where_only_one_has_value(expected &rhs, t_is_not_void) {
1858 swap_where_only_one_has_value_and_t_is_not_void(
1859 rhs, typename std::is_nothrow_move_constructible<T>::type{},
1860 typename std::is_nothrow_move_constructible<E>::type{});
1863 void swap_where_only_one_has_value_and_t_is_not_void(
1864 expected &rhs, t_is_nothrow_move_constructible,
1865 e_is_nothrow_move_constructible) noexcept {
1866 auto temp = std::move(val());
1867 val().~T();
1868 ::new (errptr()) unexpected_type(std::move(rhs.err()));
1869 rhs.err().~unexpected_type();
1870 ::new (rhs.valptr()) T(std::move(temp));
1871 std::swap(this->m_has_val, rhs.m_has_val);
1874 void swap_where_only_one_has_value_and_t_is_not_void(
1875 expected &rhs, t_is_nothrow_move_constructible,
1876 move_constructing_e_can_throw) {
1877 auto temp = std::move(val());
1878 val().~T();
1879 #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
1880 try {
1881 ::new (errptr()) unexpected_type(std::move(rhs.err()));
1882 rhs.err().~unexpected_type();
1883 ::new (rhs.valptr()) T(std::move(temp));
1884 std::swap(this->m_has_val, rhs.m_has_val);
1885 } catch (...) {
1886 val() = std::move(temp);
1887 throw;
1889 #else
1890 ::new (errptr()) unexpected_type(std::move(rhs.err()));
1891 rhs.err().~unexpected_type();
1892 ::new (rhs.valptr()) T(std::move(temp));
1893 std::swap(this->m_has_val, rhs.m_has_val);
1894 #endif
1897 void swap_where_only_one_has_value_and_t_is_not_void(
1898 expected &rhs, move_constructing_t_can_throw,
1899 e_is_nothrow_move_constructible) {
1900 auto temp = std::move(rhs.err());
1901 rhs.err().~unexpected_type();
1902 #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
1903 try {
1904 ::new (rhs.valptr()) T(std::move(val()));
1905 val().~T();
1906 ::new (errptr()) unexpected_type(std::move(temp));
1907 std::swap(this->m_has_val, rhs.m_has_val);
1908 } catch (...) {
1909 rhs.err() = std::move(temp);
1910 throw;
1912 #else
1913 ::new (rhs.valptr()) T(std::move(val()));
1914 val().~T();
1915 ::new (errptr()) unexpected_type(std::move(temp));
1916 std::swap(this->m_has_val, rhs.m_has_val);
1917 #endif
1920 public:
1921 template <class OT = T, class OE = E>
1922 detail::enable_if_t<detail::is_swappable<OT>::value &&
1923 detail::is_swappable<OE>::value &&
1924 (std::is_nothrow_move_constructible<OT>::value ||
1925 std::is_nothrow_move_constructible<OE>::value)>
1926 swap(expected &rhs) noexcept(
1927 std::is_nothrow_move_constructible<T>::value
1928 &&detail::is_nothrow_swappable<T>::value
1929 &&std::is_nothrow_move_constructible<E>::value
1930 &&detail::is_nothrow_swappable<E>::value) {
1931 if (has_value() && rhs.has_value()) {
1932 swap_where_both_have_value(rhs, typename std::is_void<T>::type{});
1933 } else if (!has_value() && rhs.has_value()) {
1934 rhs.swap(*this);
1935 } else if (has_value()) {
1936 swap_where_only_one_has_value(rhs, typename std::is_void<T>::type{});
1937 } else {
1938 using std::swap;
1939 swap(err(), rhs.err());
1943 constexpr const T *operator->() const {
1944 TL_ASSERT(has_value());
1945 return valptr();
1947 TL_EXPECTED_11_CONSTEXPR T *operator->() {
1948 TL_ASSERT(has_value());
1949 return valptr();
1952 template <class U = T,
1953 detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
1954 constexpr const U &operator*() const & {
1955 TL_ASSERT(has_value());
1956 return val();
1958 template <class U = T,
1959 detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
1960 TL_EXPECTED_11_CONSTEXPR U &operator*() & {
1961 TL_ASSERT(has_value());
1962 return val();
1964 template <class U = T,
1965 detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
1966 constexpr const U &&operator*() const && {
1967 TL_ASSERT(has_value());
1968 return std::move(val());
1970 template <class U = T,
1971 detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
1972 TL_EXPECTED_11_CONSTEXPR U &&operator*() && {
1973 TL_ASSERT(has_value());
1974 return std::move(val());
1977 constexpr bool has_value() const noexcept { return this->m_has_val; }
1978 constexpr explicit operator bool() const noexcept { return this->m_has_val; }
1980 template <class U = T,
1981 detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
1982 TL_EXPECTED_11_CONSTEXPR const U &value() const & {
1983 if (!has_value())
1984 detail::throw_exception(bad_expected_access<E>(err().value()));
1985 return val();
1987 template <class U = T,
1988 detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
1989 TL_EXPECTED_11_CONSTEXPR U &value() & {
1990 if (!has_value())
1991 detail::throw_exception(bad_expected_access<E>(err().value()));
1992 return val();
1994 template <class U = T,
1995 detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
1996 TL_EXPECTED_11_CONSTEXPR const U &&value() const && {
1997 if (!has_value())
1998 detail::throw_exception(bad_expected_access<E>(std::move(err()).value()));
1999 return std::move(val());
2001 template <class U = T,
2002 detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
2003 TL_EXPECTED_11_CONSTEXPR U &&value() && {
2004 if (!has_value())
2005 detail::throw_exception(bad_expected_access<E>(std::move(err()).value()));
2006 return std::move(val());
2009 constexpr const E &error() const & {
2010 TL_ASSERT(!has_value());
2011 return err().value();
2013 TL_EXPECTED_11_CONSTEXPR E &error() & {
2014 TL_ASSERT(!has_value());
2015 return err().value();
2017 constexpr const E &&error() const && {
2018 TL_ASSERT(!has_value());
2019 return std::move(err().value());
2021 TL_EXPECTED_11_CONSTEXPR E &&error() && {
2022 TL_ASSERT(!has_value());
2023 return std::move(err().value());
2026 template <class U> constexpr T value_or(U &&v) const & {
2027 static_assert(std::is_copy_constructible<T>::value &&
2028 std::is_convertible<U &&, T>::value,
2029 "T must be copy-constructible and convertible to from U&&");
2030 return bool(*this) ? **this : static_cast<T>(std::forward<U>(v));
2032 template <class U> TL_EXPECTED_11_CONSTEXPR T value_or(U &&v) && {
2033 static_assert(std::is_move_constructible<T>::value &&
2034 std::is_convertible<U &&, T>::value,
2035 "T must be move-constructible and convertible to from U&&");
2036 return bool(*this) ? std::move(**this) : static_cast<T>(std::forward<U>(v));
2040 namespace detail {
2041 template <class Exp> using exp_t = typename detail::decay_t<Exp>::value_type;
2042 template <class Exp> using err_t = typename detail::decay_t<Exp>::error_type;
2043 template <class Exp, class Ret> using ret_t = expected<Ret, err_t<Exp>>;
2045 #ifdef TL_EXPECTED_CXX14
2046 template <class Exp, class F,
2047 detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
2048 class Ret = decltype(detail::invoke(std::declval<F>(),
2049 *std::declval<Exp>()))>
2050 constexpr auto and_then_impl(Exp &&exp, F &&f) {
2051 static_assert(detail::is_expected<Ret>::value, "F must return an expected");
2053 return exp.has_value()
2054 ? detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp))
2055 : Ret(unexpect, std::forward<Exp>(exp).error());
2058 template <class Exp, class F,
2059 detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
2060 class Ret = decltype(detail::invoke(std::declval<F>()))>
2061 constexpr auto and_then_impl(Exp &&exp, F &&f) {
2062 static_assert(detail::is_expected<Ret>::value, "F must return an expected");
2064 return exp.has_value() ? detail::invoke(std::forward<F>(f))
2065 : Ret(unexpect, std::forward<Exp>(exp).error());
2067 #else
2068 template <class> struct TC;
2069 template <class Exp, class F,
2070 class Ret = decltype(detail::invoke(std::declval<F>(),
2071 *std::declval<Exp>())),
2072 detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr>
2073 auto and_then_impl(Exp &&exp, F &&f) -> Ret {
2074 static_assert(detail::is_expected<Ret>::value, "F must return an expected");
2076 return exp.has_value()
2077 ? detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp))
2078 : Ret(unexpect, std::forward<Exp>(exp).error());
2081 template <class Exp, class F,
2082 class Ret = decltype(detail::invoke(std::declval<F>())),
2083 detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr>
2084 constexpr auto and_then_impl(Exp &&exp, F &&f) -> Ret {
2085 static_assert(detail::is_expected<Ret>::value, "F must return an expected");
2087 return exp.has_value() ? detail::invoke(std::forward<F>(f))
2088 : Ret(unexpect, std::forward<Exp>(exp).error());
2090 #endif
2092 #ifdef TL_EXPECTED_CXX14
2093 template <class Exp, class F,
2094 detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
2095 class Ret = decltype(detail::invoke(std::declval<F>(),
2096 *std::declval<Exp>())),
2097 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2098 constexpr auto expected_map_impl(Exp &&exp, F &&f) {
2099 using result = ret_t<Exp, detail::decay_t<Ret>>;
2100 return exp.has_value() ? result(detail::invoke(std::forward<F>(f),
2101 *std::forward<Exp>(exp)))
2102 : result(unexpect, std::forward<Exp>(exp).error());
2105 template <class Exp, class F,
2106 detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
2107 class Ret = decltype(detail::invoke(std::declval<F>(),
2108 *std::declval<Exp>())),
2109 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2110 auto expected_map_impl(Exp &&exp, F &&f) {
2111 using result = expected<void, err_t<Exp>>;
2112 if (exp.has_value()) {
2113 detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp));
2114 return result();
2117 return result(unexpect, std::forward<Exp>(exp).error());
2120 template <class Exp, class F,
2121 detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
2122 class Ret = decltype(detail::invoke(std::declval<F>())),
2123 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2124 constexpr auto expected_map_impl(Exp &&exp, F &&f) {
2125 using result = ret_t<Exp, detail::decay_t<Ret>>;
2126 return exp.has_value() ? result(detail::invoke(std::forward<F>(f)))
2127 : result(unexpect, std::forward<Exp>(exp).error());
2130 template <class Exp, class F,
2131 detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
2132 class Ret = decltype(detail::invoke(std::declval<F>())),
2133 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2134 auto expected_map_impl(Exp &&exp, F &&f) {
2135 using result = expected<void, err_t<Exp>>;
2136 if (exp.has_value()) {
2137 detail::invoke(std::forward<F>(f));
2138 return result();
2141 return result(unexpect, std::forward<Exp>(exp).error());
2143 #else
2144 template <class Exp, class F,
2145 detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
2146 class Ret = decltype(detail::invoke(std::declval<F>(),
2147 *std::declval<Exp>())),
2148 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2150 constexpr auto expected_map_impl(Exp &&exp, F &&f)
2151 -> ret_t<Exp, detail::decay_t<Ret>> {
2152 using result = ret_t<Exp, detail::decay_t<Ret>>;
2154 return exp.has_value() ? result(detail::invoke(std::forward<F>(f),
2155 *std::forward<Exp>(exp)))
2156 : result(unexpect, std::forward<Exp>(exp).error());
2159 template <class Exp, class F,
2160 detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
2161 class Ret = decltype(detail::invoke(std::declval<F>(),
2162 *std::declval<Exp>())),
2163 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2165 auto expected_map_impl(Exp &&exp, F &&f) -> expected<void, err_t<Exp>> {
2166 if (exp.has_value()) {
2167 detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp));
2168 return {};
2171 return unexpected<err_t<Exp>>(std::forward<Exp>(exp).error());
2174 template <class Exp, class F,
2175 detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
2176 class Ret = decltype(detail::invoke(std::declval<F>())),
2177 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2179 constexpr auto expected_map_impl(Exp &&exp, F &&f)
2180 -> ret_t<Exp, detail::decay_t<Ret>> {
2181 using result = ret_t<Exp, detail::decay_t<Ret>>;
2183 return exp.has_value() ? result(detail::invoke(std::forward<F>(f)))
2184 : result(unexpect, std::forward<Exp>(exp).error());
2187 template <class Exp, class F,
2188 detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
2189 class Ret = decltype(detail::invoke(std::declval<F>())),
2190 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2192 auto expected_map_impl(Exp &&exp, F &&f) -> expected<void, err_t<Exp>> {
2193 if (exp.has_value()) {
2194 detail::invoke(std::forward<F>(f));
2195 return {};
2198 return unexpected<err_t<Exp>>(std::forward<Exp>(exp).error());
2200 #endif
2202 #if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
2203 !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
2204 template <class Exp, class F,
2205 detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
2206 class Ret = decltype(detail::invoke(std::declval<F>(),
2207 std::declval<Exp>().error())),
2208 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2209 constexpr auto map_error_impl(Exp &&exp, F &&f) {
2210 using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
2211 return exp.has_value()
2212 ? result(*std::forward<Exp>(exp))
2213 : result(unexpect, detail::invoke(std::forward<F>(f),
2214 std::forward<Exp>(exp).error()));
2216 template <class Exp, class F,
2217 detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
2218 class Ret = decltype(detail::invoke(std::declval<F>(),
2219 std::declval<Exp>().error())),
2220 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2221 auto map_error_impl(Exp &&exp, F &&f) {
2222 using result = expected<exp_t<Exp>, monostate>;
2223 if (exp.has_value()) {
2224 return result(*std::forward<Exp>(exp));
2227 detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
2228 return result(unexpect, monostate{});
2230 template <class Exp, class F,
2231 detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
2232 class Ret = decltype(detail::invoke(std::declval<F>(),
2233 std::declval<Exp>().error())),
2234 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2235 constexpr auto map_error_impl(Exp &&exp, F &&f) {
2236 using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
2237 return exp.has_value()
2238 ? result()
2239 : result(unexpect, detail::invoke(std::forward<F>(f),
2240 std::forward<Exp>(exp).error()));
2242 template <class Exp, class F,
2243 detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
2244 class Ret = decltype(detail::invoke(std::declval<F>(),
2245 std::declval<Exp>().error())),
2246 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2247 auto map_error_impl(Exp &&exp, F &&f) {
2248 using result = expected<exp_t<Exp>, monostate>;
2249 if (exp.has_value()) {
2250 return result();
2253 detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
2254 return result(unexpect, monostate{});
2256 #else
2257 template <class Exp, class F,
2258 detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
2259 class Ret = decltype(detail::invoke(std::declval<F>(),
2260 std::declval<Exp>().error())),
2261 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2262 constexpr auto map_error_impl(Exp &&exp, F &&f)
2263 -> expected<exp_t<Exp>, detail::decay_t<Ret>> {
2264 using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
2266 return exp.has_value()
2267 ? result(*std::forward<Exp>(exp))
2268 : result(unexpect, detail::invoke(std::forward<F>(f),
2269 std::forward<Exp>(exp).error()));
2272 template <class Exp, class F,
2273 detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
2274 class Ret = decltype(detail::invoke(std::declval<F>(),
2275 std::declval<Exp>().error())),
2276 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2277 auto map_error_impl(Exp &&exp, F &&f) -> expected<exp_t<Exp>, monostate> {
2278 using result = expected<exp_t<Exp>, monostate>;
2279 if (exp.has_value()) {
2280 return result(*std::forward<Exp>(exp));
2283 detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
2284 return result(unexpect, monostate{});
2287 template <class Exp, class F,
2288 detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
2289 class Ret = decltype(detail::invoke(std::declval<F>(),
2290 std::declval<Exp>().error())),
2291 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2292 constexpr auto map_error_impl(Exp &&exp, F &&f)
2293 -> expected<exp_t<Exp>, detail::decay_t<Ret>> {
2294 using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
2296 return exp.has_value()
2297 ? result()
2298 : result(unexpect, detail::invoke(std::forward<F>(f),
2299 std::forward<Exp>(exp).error()));
2302 template <class Exp, class F,
2303 detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
2304 class Ret = decltype(detail::invoke(std::declval<F>(),
2305 std::declval<Exp>().error())),
2306 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2307 auto map_error_impl(Exp &&exp, F &&f) -> expected<exp_t<Exp>, monostate> {
2308 using result = expected<exp_t<Exp>, monostate>;
2309 if (exp.has_value()) {
2310 return result();
2313 detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
2314 return result(unexpect, monostate{});
2316 #endif
2318 #ifdef TL_EXPECTED_CXX14
2319 template <class Exp, class F,
2320 class Ret = decltype(detail::invoke(std::declval<F>(),
2321 std::declval<Exp>().error())),
2322 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2323 constexpr auto or_else_impl(Exp &&exp, F &&f) {
2324 static_assert(detail::is_expected<Ret>::value, "F must return an expected");
2325 return exp.has_value() ? std::forward<Exp>(exp)
2326 : detail::invoke(std::forward<F>(f),
2327 std::forward<Exp>(exp).error());
2330 template <class Exp, class F,
2331 class Ret = decltype(detail::invoke(std::declval<F>(),
2332 std::declval<Exp>().error())),
2333 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2334 detail::decay_t<Exp> or_else_impl(Exp &&exp, F &&f) {
2335 return exp.has_value() ? std::forward<Exp>(exp)
2336 : (detail::invoke(std::forward<F>(f),
2337 std::forward<Exp>(exp).error()),
2338 std::forward<Exp>(exp));
2340 #else
2341 template <class Exp, class F,
2342 class Ret = decltype(detail::invoke(std::declval<F>(),
2343 std::declval<Exp>().error())),
2344 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2345 auto or_else_impl(Exp &&exp, F &&f) -> Ret {
2346 static_assert(detail::is_expected<Ret>::value, "F must return an expected");
2347 return exp.has_value() ? std::forward<Exp>(exp)
2348 : detail::invoke(std::forward<F>(f),
2349 std::forward<Exp>(exp).error());
2352 template <class Exp, class F,
2353 class Ret = decltype(detail::invoke(std::declval<F>(),
2354 std::declval<Exp>().error())),
2355 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2356 detail::decay_t<Exp> or_else_impl(Exp &&exp, F &&f) {
2357 return exp.has_value() ? std::forward<Exp>(exp)
2358 : (detail::invoke(std::forward<F>(f),
2359 std::forward<Exp>(exp).error()),
2360 std::forward<Exp>(exp));
2362 #endif
2363 } // namespace detail
2365 template <class T, class E, class U, class F>
2366 constexpr bool operator==(const expected<T, E> &lhs,
2367 const expected<U, F> &rhs) {
2368 return (lhs.has_value() != rhs.has_value())
2369 ? false
2370 : (!lhs.has_value() ? lhs.error() == rhs.error() : *lhs == *rhs);
2372 template <class T, class E, class U, class F>
2373 constexpr bool operator!=(const expected<T, E> &lhs,
2374 const expected<U, F> &rhs) {
2375 return (lhs.has_value() != rhs.has_value())
2376 ? true
2377 : (!lhs.has_value() ? lhs.error() != rhs.error() : *lhs != *rhs);
2379 template <class E, class F>
2380 constexpr bool operator==(const expected<void, E> &lhs,
2381 const expected<void, F> &rhs) {
2382 return (lhs.has_value() != rhs.has_value())
2383 ? false
2384 : (!lhs.has_value() ? lhs.error() == rhs.error() : true);
2386 template <class E, class F>
2387 constexpr bool operator!=(const expected<void, E> &lhs,
2388 const expected<void, F> &rhs) {
2389 return (lhs.has_value() != rhs.has_value())
2390 ? true
2391 : (!lhs.has_value() ? lhs.error() == rhs.error() : false);
2394 template <class T, class E, class U>
2395 constexpr bool operator==(const expected<T, E> &x, const U &v) {
2396 return x.has_value() ? *x == v : false;
2398 template <class T, class E, class U>
2399 constexpr bool operator==(const U &v, const expected<T, E> &x) {
2400 return x.has_value() ? *x == v : false;
2402 template <class T, class E, class U>
2403 constexpr bool operator!=(const expected<T, E> &x, const U &v) {
2404 return x.has_value() ? *x != v : true;
2406 template <class T, class E, class U>
2407 constexpr bool operator!=(const U &v, const expected<T, E> &x) {
2408 return x.has_value() ? *x != v : true;
2411 template <class T, class E>
2412 constexpr bool operator==(const expected<T, E> &x, const unexpected<E> &e) {
2413 return x.has_value() ? false : x.error() == e.value();
2415 template <class T, class E>
2416 constexpr bool operator==(const unexpected<E> &e, const expected<T, E> &x) {
2417 return x.has_value() ? false : x.error() == e.value();
2419 template <class T, class E>
2420 constexpr bool operator!=(const expected<T, E> &x, const unexpected<E> &e) {
2421 return x.has_value() ? true : x.error() != e.value();
2423 template <class T, class E>
2424 constexpr bool operator!=(const unexpected<E> &e, const expected<T, E> &x) {
2425 return x.has_value() ? true : x.error() != e.value();
2428 template <class T, class E,
2429 detail::enable_if_t<(std::is_void<T>::value ||
2430 std::is_move_constructible<T>::value) &&
2431 detail::is_swappable<T>::value &&
2432 std::is_move_constructible<E>::value &&
2433 detail::is_swappable<E>::value> * = nullptr>
2434 void swap(expected<T, E> &lhs,
2435 expected<T, E> &rhs) noexcept(noexcept(lhs.swap(rhs))) {
2436 lhs.swap(rhs);
2438 } // namespace tl
2440 #endif