M5Utility 0.2.0 git rev:301a6b5
Loading...
Searching...
No Matches
expected.hpp
1
2// expected - An implementation of m5::stl::expected with extensions
3// Written in 2017 by Sy Brand (tartanllama@gmail.com, @TartanLlama)
4//
5// Documentation available at http://tl.tartanllama.xyz/
6//
7// To the extent possible under law, the author(s) have dedicated all
8// copyright and related and neighboring rights to this software to the
9// public domain worldwide. This software is distributed without any warranty.
10//
11// You should have received a copy of the CC0 Public Domain Dedication
12// along with this software. If not, see
13// <http://creativecommons.org/publicdomain/zero/1.0/>.
15//
16// Modified for M5 Utility by M5Stack
17//
19#ifndef M5_UTILITY_STL_EXPECTED_HPP
20#define M5_UTILITY_STL_EXPECTED_HPP
21
22#define TL_EXPECTED_VERSION_MAJOR 1
23#define TL_EXPECTED_VERSION_MINOR 1
24#define TL_EXPECTED_VERSION_PATCH 0
25
26#include <exception>
27#include <functional>
28#include <type_traits>
29#include <utility>
30
31#if defined(__EXCEPTIONS) || defined(_CPPUNWIND)
32#define TL_EXPECTED_EXCEPTIONS_ENABLED
33#endif
34
35#if (defined(_MSC_VER) && _MSC_VER == 1900)
36#define TL_EXPECTED_MSVC2015
37#define TL_EXPECTED_MSVC2015_CONSTEXPR
38#else
39#define TL_EXPECTED_MSVC2015_CONSTEXPR constexpr
40#endif
41
42#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && !defined(__clang__))
43#define TL_EXPECTED_GCC49
44#endif
45
46#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && !defined(__clang__))
47#define TL_EXPECTED_GCC54
48#endif
49
50#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 5 && !defined(__clang__))
51#define TL_EXPECTED_GCC55
52#endif
53
54#if !defined(TL_ASSERT)
55// can't have assert in constexpr in C++11 and GCC 4.9 has a compiler bug
56// ESP8266's newlib assert() expands PSTR() — a static array declaration
57// inside the expression — which is ill-formed in constexpr functions, so
58// that toolchain gets the no-op fallback too.
59#if (__cplusplus > 201103L) && !defined(TL_EXPECTED_GCC49) && !defined(ESP8266)
60#include <cassert>
61#define TL_ASSERT(x) assert(x)
62#else
63#define TL_ASSERT(x)
64#endif
65#endif
66
67#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && !defined(__clang__))
68// GCC < 5 doesn't support overloading on const&& for member functions
69
70#define TL_EXPECTED_NO_CONSTRR
71// GCC < 5 doesn't support some standard C++11 type traits
72#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) std::has_trivial_copy_constructor<T>
73#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) std::has_trivial_copy_assign<T>
74
75// This one will be different for GCC 5.7 if it's ever supported
76#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible<T>
77
78// GCC 5 < v < 8 has a bug in is_trivially_copy_constructible which breaks
79// std::vector for non-copyable types
80#elif (defined(__GNUC__) && __GNUC__ < 8 && !defined(__clang__))
81#ifndef TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
82#define TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
83namespace m5 {
84namespace stl {
85namespace detail {
86template <class T>
87struct is_trivially_copy_constructible : std::is_trivially_copy_constructible<T> {};
88#ifdef _GLIBCXX_VECTOR
89template <class T, class A>
90struct is_trivially_copy_constructible<std::vector<T, A>> : std::false_type {};
91#endif
92} // namespace detail
93} // namespace stl
94} // namespace m5
95#endif
96
97#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) stl::detail::is_trivially_copy_constructible<T>
98#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) std::is_trivially_copy_assignable<T>
99#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible<T>
100#else
101#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) std::is_trivially_copy_constructible<T>
102#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) std::is_trivially_copy_assignable<T>
103#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible<T>
104#endif
105
106#if __cplusplus > 201103L
107#define TL_EXPECTED_CXX14
108#endif
109
110#ifdef TL_EXPECTED_GCC49
111#define TL_EXPECTED_GCC49_CONSTEXPR
112#else
113#define TL_EXPECTED_GCC49_CONSTEXPR constexpr
114#endif
115
116#if (__cplusplus == 201103L || defined(TL_EXPECTED_MSVC2015) || defined(TL_EXPECTED_GCC49))
117#define TL_EXPECTED_11_CONSTEXPR
118#else
119#define TL_EXPECTED_11_CONSTEXPR constexpr
120#endif
121
122namespace m5 {
123namespace stl {
124template <class T, class E>
125class expected;
126
127#ifndef TL_MONOSTATE_INPLACE_MUTEX
128#define TL_MONOSTATE_INPLACE_MUTEX
129class monostate {};
130
131struct in_place_t {
132 explicit in_place_t() = default;
133};
134static constexpr in_place_t in_place{};
135#endif
136
137template <class E>
139public:
140 static_assert(!std::is_same<E, void>::value, "E must not be void");
141
142 unexpected() = delete;
143 constexpr explicit unexpected(const E &e) : m_val(e)
144 {
145 }
146
147 constexpr explicit unexpected(E &&e) : m_val(std::move(e))
148 {
149 }
150
151 template <class... Args, typename std::enable_if<std::is_constructible<E, Args &&...>::value>::type * = nullptr>
152 constexpr explicit unexpected(Args &&...args) : m_val(std::forward<Args>(args)...)
153 {
154 }
155 template <class U, class... Args,
156 typename std::enable_if<std::is_constructible<E, std::initializer_list<U> &, Args &&...>::value>::type * =
157 nullptr>
158 constexpr explicit unexpected(std::initializer_list<U> l, Args &&...args) : m_val(l, std::forward<Args>(args)...)
159 {
160 }
161
162 constexpr const E &value() const &
163 {
164 return m_val;
165 }
166 TL_EXPECTED_11_CONSTEXPR E &value() &
167 {
168 return m_val;
169 }
170 TL_EXPECTED_11_CONSTEXPR E &&value() &&
171 {
172 return std::move(m_val);
173 }
174 constexpr const E &&value() const &&
175 {
176 return std::move(m_val);
177 }
178
179private:
180 E m_val;
181};
182
183#ifdef __cpp_deduction_guides
184template <class E>
186#endif
187
188template <class E>
189constexpr bool operator==(const unexpected<E> &lhs, const unexpected<E> &rhs)
190{
191 return lhs.value() == rhs.value();
192}
193template <class E>
194constexpr bool operator!=(const unexpected<E> &lhs, const unexpected<E> &rhs)
195{
196 return lhs.value() != rhs.value();
197}
198template <class E>
199constexpr bool operator<(const unexpected<E> &lhs, const unexpected<E> &rhs)
200{
201 return lhs.value() < rhs.value();
202}
203template <class E>
204constexpr bool operator<=(const unexpected<E> &lhs, const unexpected<E> &rhs)
205{
206 return lhs.value() <= rhs.value();
207}
208template <class E>
209constexpr bool operator>(const unexpected<E> &lhs, const unexpected<E> &rhs)
210{
211 return lhs.value() > rhs.value();
212}
213template <class E>
214constexpr bool operator>=(const unexpected<E> &lhs, const unexpected<E> &rhs)
215{
216 return lhs.value() >= rhs.value();
217}
218
219template <class E>
220unexpected<typename std::decay<E>::type> make_unexpected(E &&e)
221{
222 return unexpected<typename std::decay<E>::type>(std::forward<E>(e));
223}
224
226 unexpect_t() = default;
227};
228static constexpr unexpect_t unexpect{};
229
230namespace detail {
231template <typename E>
232[[noreturn]] TL_EXPECTED_11_CONSTEXPR void throw_exception(E &&e)
233{
234#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
235 throw std::forward<E>(e);
236#else
237 (void)e;
238#ifdef _MSC_VER
239 __assume(0);
240#else
241 __builtin_unreachable();
242#endif
243#endif
244}
245
246#ifndef TL_TRAITS_MUTEX
247#define TL_TRAITS_MUTEX
248// C++14-style aliases for brevity
249template <class T>
250using remove_const_t = typename std::remove_const<T>::type;
251template <class T>
252using remove_reference_t = typename std::remove_reference<T>::type;
253template <class T>
254using decay_t = typename std::decay<T>::type;
255template <bool E, class T = void>
256using enable_if_t = typename std::enable_if<E, T>::type;
257template <bool B, class T, class F>
258using conditional_t = typename std::conditional<B, T, F>::type;
259
260// std::conjunction from C++17
261template <class...>
262struct conjunction : std::true_type {};
263template <class B>
264struct conjunction<B> : B {};
265template <class B, class... Bs>
266struct conjunction<B, Bs...> : std::conditional<bool(B::value), conjunction<Bs...>, B>::type {};
267
268#if defined(_LIBCPP_VERSION) && __cplusplus == 201103L
269#define TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
270#endif
271
272// In C++11 mode, there's an issue in libc++'s std::mem_fn
273// which results in a hard-error when using it in a noexcept expression
274// in some cases. This is a check to workaround the common failing case.
275#ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
276template <class T>
277struct is_pointer_to_non_const_member_func : std::false_type {};
278template <class T, class Ret, class... Args>
279struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...)> : std::true_type {};
280template <class T, class Ret, class... Args>
281struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) &> : std::true_type {};
282template <class T, class Ret, class... Args>
283struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) &&> : std::true_type {};
284template <class T, class Ret, class... Args>
285struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile> : std::true_type {};
286template <class T, class Ret, class... Args>
287struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile &> : std::true_type {};
288template <class T, class Ret, class... Args>
289struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile &&> : std::true_type {};
290
291template <class T>
292struct is_const_or_const_ref : std::false_type {};
293template <class T>
294struct is_const_or_const_ref<T const &> : std::true_type {};
295template <class T>
296struct is_const_or_const_ref<T const> : std::true_type {};
297#endif
298
299// std::invoke from C++17
300// https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround
301template <
302 typename Fn, typename... Args,
303#ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
304 typename = enable_if_t<!(is_pointer_to_non_const_member_func<Fn>::value && is_const_or_const_ref<Args...>::value)>,
305#endif
306 typename = enable_if_t<std::is_member_pointer<decay_t<Fn>>::value>, int = 0>
307constexpr auto invoke(Fn &&f, Args &&...args) noexcept(noexcept(std::mem_fn(f)(std::forward<Args>(args)...)))
308 -> decltype(std::mem_fn(f)(std::forward<Args>(args)...))
309{
310 return std::mem_fn(f)(std::forward<Args>(args)...);
311}
312
313template <typename Fn, typename... Args, typename = enable_if_t<!std::is_member_pointer<decay_t<Fn>>::value>>
314constexpr auto invoke(Fn &&f, Args &&...args) noexcept(noexcept(std::forward<Fn>(f)(std::forward<Args>(args)...)))
315 -> decltype(std::forward<Fn>(f)(std::forward<Args>(args)...))
316{
317 return std::forward<Fn>(f)(std::forward<Args>(args)...);
318}
319
320// std::invoke_result from C++17
321template <class F, class, class... Us>
322struct invoke_result_impl;
323
324template <class F, class... Us>
325struct invoke_result_impl<F, decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...), void()), Us...> {
326 using type = decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...));
327};
328
329template <class F, class... Us>
330using invoke_result = invoke_result_impl<F, void, Us...>;
331
332template <class F, class... Us>
333using invoke_result_t = typename invoke_result<F, Us...>::type;
334
335#if defined(_MSC_VER) && _MSC_VER <= 1900
336// TODO make a version which works with MSVC 2015
337template <class T, class U = T>
338struct is_swappable : std::true_type {};
339
340template <class T, class U = T>
341struct is_nothrow_swappable : std::true_type {};
342#else
343// https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept
344namespace swap_adl_tests {
345// if swap ADL finds this then it would call std::swap otherwise (same
346// signature)
347struct tag {};
348
349template <class T>
350tag swap(T &, T &);
351template <class T, std::size_t N>
352tag swap(T (&a)[N], T (&b)[N]);
353
354// helper functions to test if an unqualified swap is possible, and if it
355// becomes std::swap
356template <class, class>
357std::false_type can_swap(...) noexcept(false);
358template <class T, class U, class = decltype(swap(std::declval<T &>(), std::declval<U &>()))>
359std::true_type can_swap(int) noexcept(noexcept(swap(std::declval<T &>(), std::declval<U &>())));
360
361template <class, class>
362std::false_type uses_std(...);
363template <class T, class U>
364std::is_same<decltype(swap(std::declval<T &>(), std::declval<U &>())), tag> uses_std(int);
365
366template <class T>
367struct is_std_swap_noexcept : std::integral_constant<bool, std::is_nothrow_move_constructible<T>::value &&
368 std::is_nothrow_move_assignable<T>::value> {};
369
370template <class T, std::size_t N>
371struct is_std_swap_noexcept<T[N]> : is_std_swap_noexcept<T> {};
372
373template <class T, class U>
374struct is_adl_swap_noexcept : std::integral_constant<bool, noexcept(can_swap<T, U>(0))> {};
375} // namespace swap_adl_tests
376
377template <class T, class U = T>
378struct is_swappable
379 : std::integral_constant<bool, decltype(detail::swap_adl_tests::can_swap<T, U>(0))::value &&
380 (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value ||
381 (std::is_move_assignable<T>::value && std::is_move_constructible<T>::value))> {
382};
383
384template <class T, std::size_t N>
385struct is_swappable<T[N], T[N]>
386 : std::integral_constant<bool, decltype(detail::swap_adl_tests::can_swap<T[N], T[N]>(0))::value &&
387 (!decltype(detail::swap_adl_tests::uses_std<T[N], T[N]>(0))::value ||
388 is_swappable<T, T>::value)> {};
389
390template <class T, class U = T>
391struct is_nothrow_swappable
392 : std::integral_constant<bool, is_swappable<T, U>::value &&
393 ((decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value &&
394 detail::swap_adl_tests::is_std_swap_noexcept<T>::value) ||
395 (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value &&
396 detail::swap_adl_tests::is_adl_swap_noexcept<T, U>::value))> {};
397#endif
398#endif
399
400// Trait for checking if a type is a tl::expected
401template <class T>
402struct is_expected_impl : std::false_type {};
403template <class T, class E>
404struct is_expected_impl<expected<T, E>> : std::true_type {};
405template <class T>
407
408template <class T, class E, class U>
409using expected_enable_forward_value =
410 detail::enable_if_t<std::is_constructible<T, U &&>::value && !std::is_same<detail::decay_t<U>, in_place_t>::value &&
411 !std::is_same<expected<T, E>, detail::decay_t<U>>::value &&
412 !std::is_same<unexpected<E>, detail::decay_t<U>>::value>;
413
414template <class T, class E, class U, class G, class UR, class GR>
415using expected_enable_from_other = detail::enable_if_t<
416 std::is_constructible<T, UR>::value && std::is_constructible<E, GR>::value &&
417 !std::is_constructible<T, expected<U, G> &>::value && !std::is_constructible<T, expected<U, G> &&>::value &&
418 !std::is_constructible<T, const expected<U, G> &>::value &&
419 !std::is_constructible<T, const expected<U, G> &&>::value && !std::is_convertible<expected<U, G> &, T>::value &&
420 !std::is_convertible<expected<U, G> &&, T>::value && !std::is_convertible<const expected<U, G> &, T>::value &&
421 !std::is_convertible<const expected<U, G> &&, T>::value>;
422
423template <class T, class U>
424using is_void_or = conditional_t<std::is_void<T>::value, std::true_type, U>;
425
426template <class T>
427using is_copy_constructible_or_void = is_void_or<T, std::is_copy_constructible<T>>;
428
429template <class T>
430using is_move_constructible_or_void = is_void_or<T, std::is_move_constructible<T>>;
431
432template <class T>
433using is_copy_assignable_or_void = is_void_or<T, std::is_copy_assignable<T>>;
434
435template <class T>
436using is_move_assignable_or_void = is_void_or<T, std::is_move_assignable<T>>;
437
438} // namespace detail
439
440namespace detail {
441struct no_init_t {};
442static constexpr no_init_t no_init{};
443
444// Implements the storage of the values, and ensures that the destructor is
445// trivial if it can be.
446//
447// This specialization is for where neither `T` or `E` is trivially
448// destructible, so the destructors must be called on destruction of the
449// `expected`
450template <class T, class E, bool = std::is_trivially_destructible<T>::value,
451 bool = std::is_trivially_destructible<E>::value>
453 constexpr expected_storage_base() : m_val(T{}), m_has_val(true)
454 {
455 }
456 constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false)
457 {
458 }
459
460 template <class... Args, detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * = nullptr>
461 constexpr expected_storage_base(in_place_t, Args &&...args) : m_val(std::forward<Args>(args)...), m_has_val(true)
462 {
463 }
464
465 template <class U, class... Args,
466 detail::enable_if_t<std::is_constructible<T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
467 constexpr expected_storage_base(in_place_t, std::initializer_list<U> il, Args &&...args)
468 : m_val(il, std::forward<Args>(args)...), m_has_val(true)
469 {
470 }
471 template <class... Args, detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * = nullptr>
472 constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
473 : m_unexpect(std::forward<Args>(args)...), m_has_val(false)
474 {
475 }
476
477 template <class U, class... Args,
478 detail::enable_if_t<std::is_constructible<E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
479 constexpr explicit expected_storage_base(unexpect_t, std::initializer_list<U> il, Args &&...args)
480 : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false)
481 {
482 }
483
485 {
486 if (m_has_val) {
487 m_val.~T();
488 } else {
489 m_unexpect.~unexpected<E>();
490 }
491 }
492 union {
493 T m_val;
494 unexpected<E> m_unexpect;
495 char m_no_init;
496 };
497 bool m_has_val;
498};
499
500// This specialization is for when both `T` and `E` are trivially-destructible,
501// so the destructor of the `expected` can be trivial.
502template <class T, class E>
503struct expected_storage_base<T, E, true, true> {
504 constexpr expected_storage_base() : m_val(T{}), m_has_val(true)
505 {
506 }
507 constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false)
508 {
509 }
510
511 template <class... Args, detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * = nullptr>
512 constexpr expected_storage_base(in_place_t, Args &&...args) : m_val(std::forward<Args>(args)...), m_has_val(true)
513 {
514 }
515
516 template <class U, class... Args,
517 detail::enable_if_t<std::is_constructible<T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
518 constexpr expected_storage_base(in_place_t, std::initializer_list<U> il, Args &&...args)
519 : m_val(il, std::forward<Args>(args)...), m_has_val(true)
520 {
521 }
522 template <class... Args, detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * = nullptr>
523 constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
524 : m_unexpect(std::forward<Args>(args)...), m_has_val(false)
525 {
526 }
527
528 template <class U, class... Args,
529 detail::enable_if_t<std::is_constructible<E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
530 constexpr explicit expected_storage_base(unexpect_t, std::initializer_list<U> il, Args &&...args)
531 : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false)
532 {
533 }
534
535 ~expected_storage_base() = default;
536 union {
537 T m_val;
538 unexpected<E> m_unexpect;
539 char m_no_init;
540 };
541 bool m_has_val;
542};
543
544// T is trivial, E is not.
545template <class T, class E>
546struct expected_storage_base<T, E, true, false> {
547 constexpr expected_storage_base() : m_val(T{}), m_has_val(true)
548 {
549 }
550 TL_EXPECTED_MSVC2015_CONSTEXPR expected_storage_base(no_init_t) : m_no_init(), m_has_val(false)
551 {
552 }
553
554 template <class... Args, detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * = nullptr>
555 constexpr expected_storage_base(in_place_t, Args &&...args) : m_val(std::forward<Args>(args)...), m_has_val(true)
556 {
557 }
558
559 template <class U, class... Args,
560 detail::enable_if_t<std::is_constructible<T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
561 constexpr expected_storage_base(in_place_t, std::initializer_list<U> il, Args &&...args)
562 : m_val(il, std::forward<Args>(args)...), m_has_val(true)
563 {
564 }
565 template <class... Args, detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * = nullptr>
566 constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
567 : m_unexpect(std::forward<Args>(args)...), m_has_val(false)
568 {
569 }
570
571 template <class U, class... Args,
572 detail::enable_if_t<std::is_constructible<E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
573 constexpr explicit expected_storage_base(unexpect_t, std::initializer_list<U> il, Args &&...args)
574 : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false)
575 {
576 }
577
579 {
580 if (!m_has_val) {
581 m_unexpect.~unexpected<E>();
582 }
583 }
584
585 union {
586 T m_val;
587 unexpected<E> m_unexpect;
588 char m_no_init;
589 };
590 bool m_has_val;
591};
592
593// E is trivial, T is not.
594template <class T, class E>
595struct expected_storage_base<T, E, false, true> {
596 constexpr expected_storage_base() : m_val(T{}), m_has_val(true)
597 {
598 }
599 constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false)
600 {
601 }
602
603 template <class... Args, detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * = nullptr>
604 constexpr expected_storage_base(in_place_t, Args &&...args) : m_val(std::forward<Args>(args)...), m_has_val(true)
605 {
606 }
607
608 template <class U, class... Args,
609 detail::enable_if_t<std::is_constructible<T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
610 constexpr expected_storage_base(in_place_t, std::initializer_list<U> il, Args &&...args)
611 : m_val(il, std::forward<Args>(args)...), m_has_val(true)
612 {
613 }
614 template <class... Args, detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * = nullptr>
615 constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
616 : m_unexpect(std::forward<Args>(args)...), m_has_val(false)
617 {
618 }
619
620 template <class U, class... Args,
621 detail::enable_if_t<std::is_constructible<E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
622 constexpr explicit expected_storage_base(unexpect_t, std::initializer_list<U> il, Args &&...args)
623 : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false)
624 {
625 }
626
628 {
629 if (m_has_val) {
630 m_val.~T();
631 }
632 }
633 union {
634 T m_val;
635 unexpected<E> m_unexpect;
636 char m_no_init;
637 };
638 bool m_has_val;
639};
640
641// `T` is `void`, `E` is trivially-destructible
642template <class E>
643struct expected_storage_base<void, E, false, true> {
644#if __GNUC__ <= 5
645// no constexpr for GCC 4/5 bug
646#else
647 TL_EXPECTED_MSVC2015_CONSTEXPR
648#endif
649 expected_storage_base() : m_has_val(true)
650 {
651 }
652
653 constexpr expected_storage_base(no_init_t) : m_val(), m_has_val(false)
654 {
655 }
656
657 constexpr expected_storage_base(in_place_t) : m_has_val(true)
658 {
659 }
660
661 template <class... Args, detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * = nullptr>
662 constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
663 : m_unexpect(std::forward<Args>(args)...), m_has_val(false)
664 {
665 }
666
667 template <class U, class... Args,
668 detail::enable_if_t<std::is_constructible<E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
669 constexpr explicit expected_storage_base(unexpect_t, std::initializer_list<U> il, Args &&...args)
670 : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false)
671 {
672 }
673
674 ~expected_storage_base() = default;
675 struct dummy {};
676 union {
677 unexpected<E> m_unexpect;
678 dummy m_val;
679 };
680 bool m_has_val;
681};
682
683// `T` is `void`, `E` is not trivially-destructible
684template <class E>
685struct expected_storage_base<void, E, false, false> {
686 constexpr expected_storage_base() : m_dummy(), m_has_val(true)
687 {
688 }
689 constexpr expected_storage_base(no_init_t) : m_dummy(), m_has_val(false)
690 {
691 }
692
693 constexpr expected_storage_base(in_place_t) : m_dummy(), m_has_val(true)
694 {
695 }
696
697 template <class... Args, detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * = nullptr>
698 constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
699 : m_unexpect(std::forward<Args>(args)...), m_has_val(false)
700 {
701 }
702
703 template <class U, class... Args,
704 detail::enable_if_t<std::is_constructible<E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
705 constexpr explicit expected_storage_base(unexpect_t, std::initializer_list<U> il, Args &&...args)
706 : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false)
707 {
708 }
709
711 {
712 if (!m_has_val) {
713 m_unexpect.~unexpected<E>();
714 }
715 }
716
717 union {
718 unexpected<E> m_unexpect;
719 char m_dummy;
720 };
721 bool m_has_val;
722};
723
724// This base class provides some handy member functions which can be used in
725// further derived classes
726template <class T, class E>
728 using expected_storage_base<T, E>::expected_storage_base;
729
730 template <class... Args>
731 void construct(Args &&...args) noexcept
732 {
733 new (std::addressof(this->m_val)) T(std::forward<Args>(args)...);
734 this->m_has_val = true;
735 }
736
737 template <class Rhs>
738 void construct_with(Rhs &&rhs) noexcept
739 {
740 new (std::addressof(this->m_val)) T(std::forward<Rhs>(rhs).get());
741 this->m_has_val = true;
742 }
743
744 template <class... Args>
745 void construct_error(Args &&...args) noexcept
746 {
747 new (std::addressof(this->m_unexpect)) unexpected<E>(std::forward<Args>(args)...);
748 this->m_has_val = false;
749 }
750
751#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
752
753 // These assign overloads ensure that the most efficient assignment
754 // implementation is used while maintaining the strong exception guarantee.
755 // The problematic case is where rhs has a value, but *this does not.
756 //
757 // This overload handles the case where we can just copy-construct `T`
758 // directly into place without throwing.
759 template <class U = T, detail::enable_if_t<std::is_nothrow_copy_constructible<U>::value> * = nullptr>
760 void assign(const expected_operations_base &rhs) noexcept
761 {
762 if (!this->m_has_val && rhs.m_has_val) {
763 geterr().~unexpected<E>();
764 construct(rhs.get());
765 } else {
766 assign_common(rhs);
767 }
768 }
769
770 // This overload handles the case where we can attempt to create a copy of
771 // `T`, then no-throw move it into place if the copy was successful.
772 template <class U = T, detail::enable_if_t<!std::is_nothrow_copy_constructible<U>::value &&
773 std::is_nothrow_move_constructible<U>::value> * = nullptr>
774 void assign(const expected_operations_base &rhs) noexcept
775 {
776 if (!this->m_has_val && rhs.m_has_val) {
777 T tmp = rhs.get();
778 geterr().~unexpected<E>();
779 construct(std::move(tmp));
780 } else {
781 assign_common(rhs);
782 }
783 }
784
785 // This overload is the worst-case, where we have to move-construct the
786 // unexpected value into temporary storage, then try to copy the T into place.
787 // If the construction succeeds, then everything is fine, but if it throws,
788 // then we move the old unexpected value back into place before rethrowing the
789 // exception.
790 template <class U = T, detail::enable_if_t<!std::is_nothrow_copy_constructible<U>::value &&
791 !std::is_nothrow_move_constructible<U>::value> * = nullptr>
792 void assign(const expected_operations_base &rhs)
793 {
794 if (!this->m_has_val && rhs.m_has_val) {
795 auto tmp = std::move(geterr());
796 geterr().~unexpected<E>();
797
798#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
799 try {
800 construct(rhs.get());
801 } catch (...) {
802 geterr() = std::move(tmp);
803 throw;
804 }
805#else
806 construct(rhs.get());
807#endif
808 } else {
809 assign_common(rhs);
810 }
811 }
812
813 // These overloads do the same as above, but for rvalues
814 template <class U = T, detail::enable_if_t<std::is_nothrow_move_constructible<U>::value> * = nullptr>
815 void assign(expected_operations_base &&rhs) noexcept
816 {
817 if (!this->m_has_val && rhs.m_has_val) {
818 geterr().~unexpected<E>();
819 construct(std::move(rhs).get());
820 } else {
821 assign_common(std::move(rhs));
822 }
823 }
824
825 template <class U = T, detail::enable_if_t<!std::is_nothrow_move_constructible<U>::value> * = nullptr>
826 void assign(expected_operations_base &&rhs)
827 {
828 if (!this->m_has_val && rhs.m_has_val) {
829 auto tmp = std::move(geterr());
830 geterr().~unexpected<E>();
831#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
832 try {
833 construct(std::move(rhs).get());
834 } catch (...) {
835 geterr() = std::move(tmp);
836 throw;
837 }
838#else
839 construct(std::move(rhs).get());
840#endif
841 } else {
842 assign_common(std::move(rhs));
843 }
844 }
845
846#else
847
848 // If exceptions are disabled then we can just copy-construct
849 void assign(const expected_operations_base &rhs) noexcept
850 {
851 if (!this->m_has_val && rhs.m_has_val) {
852 geterr().~unexpected<E>();
853 construct(rhs.get());
854 } else {
855 assign_common(rhs);
856 }
857 }
858
859 void assign(expected_operations_base &&rhs) noexcept
860 {
861 if (!this->m_has_val && rhs.m_has_val) {
862 geterr().~unexpected<E>();
863 construct(std::move(rhs).get());
864 } else {
865 assign_common(std::move(rhs));
866 }
867 }
868
869#endif
870
871 // The common part of move/copy assigning
872 template <class Rhs>
873 void assign_common(Rhs &&rhs)
874 {
875 if (this->m_has_val) {
876 if (rhs.m_has_val) {
877 get() = std::forward<Rhs>(rhs).get();
878 } else {
879 destroy_val();
880 construct_error(std::forward<Rhs>(rhs).geterr());
881 }
882 } else {
883 if (!rhs.m_has_val) {
884 geterr() = std::forward<Rhs>(rhs).geterr();
885 }
886 }
887 }
888
889 bool has_value() const
890 {
891 return this->m_has_val;
892 }
893
894 TL_EXPECTED_11_CONSTEXPR T &get() &
895 {
896 return this->m_val;
897 }
898 constexpr const T &get() const &
899 {
900 return this->m_val;
901 }
902 TL_EXPECTED_11_CONSTEXPR T &&get() &&
903 {
904 return std::move(this->m_val);
905 }
906#ifndef TL_EXPECTED_NO_CONSTRR
907 constexpr const T &&get() const &&
908 {
909 return std::move(this->m_val);
910 }
911#endif
912
913 TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() &
914 {
915 return this->m_unexpect;
916 }
917 constexpr const unexpected<E> &geterr() const &
918 {
919 return this->m_unexpect;
920 }
921 TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() &&
922 {
923 return std::move(this->m_unexpect);
924 }
925#ifndef TL_EXPECTED_NO_CONSTRR
926 constexpr const unexpected<E> &&geterr() const &&
927 {
928 return std::move(this->m_unexpect);
929 }
930#endif
931
932 TL_EXPECTED_11_CONSTEXPR void destroy_val()
933 {
934 get().~T();
935 }
936};
937
938// This base class provides some handy member functions which can be used in
939// further derived classes
940template <class E>
942 using expected_storage_base<void, E>::expected_storage_base;
943
944 template <class... Args>
945 void construct() noexcept
946 {
947 this->m_has_val = true;
948 }
949
950 // This function doesn't use its argument, but needs it so that code in
951 // levels above this can work independently of whether T is void
952 template <class Rhs>
953 void construct_with(Rhs &&) noexcept
954 {
955 this->m_has_val = true;
956 }
957
958 template <class... Args>
959 void construct_error(Args &&...args) noexcept
960 {
961 new (std::addressof(this->m_unexpect)) unexpected<E>(std::forward<Args>(args)...);
962 this->m_has_val = false;
963 }
964
965 template <class Rhs>
966 void assign(Rhs &&rhs) noexcept
967 {
968 if (!this->m_has_val) {
969 if (rhs.m_has_val) {
970 geterr().~unexpected<E>();
971 construct();
972 } else {
973 geterr() = std::forward<Rhs>(rhs).geterr();
974 }
975 } else {
976 if (!rhs.m_has_val) {
977 construct_error(std::forward<Rhs>(rhs).geterr());
978 }
979 }
980 }
981
982 bool has_value() const
983 {
984 return this->m_has_val;
985 }
986
987 TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() &
988 {
989 return this->m_unexpect;
990 }
991 constexpr const unexpected<E> &geterr() const &
992 {
993 return this->m_unexpect;
994 }
995 TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() &&
996 {
997 return std::move(this->m_unexpect);
998 }
999#ifndef TL_EXPECTED_NO_CONSTRR
1000 constexpr const unexpected<E> &&geterr() const &&
1001 {
1002 return std::move(this->m_unexpect);
1003 }
1004#endif
1005
1006 TL_EXPECTED_11_CONSTEXPR void destroy_val()
1007 {
1008 // no-op
1009 }
1010};
1011
1012// This class manages conditionally having a trivial copy constructor
1013// This specialization is for when T and E are trivially copy constructible
1014template <class T, class E,
1015 bool = is_void_or<T, TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T)>::value &&
1016 TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value>
1018 using expected_operations_base<T, E>::expected_operations_base;
1019};
1020
1021// This specialization is for when T or E are not trivially copy constructible
1022template <class T, class E>
1024 using expected_operations_base<T, E>::expected_operations_base;
1025
1026 expected_copy_base() = default;
1028 {
1029 if (rhs.has_value()) {
1030 this->construct_with(rhs);
1031 } else {
1032 this->construct_error(rhs.geterr());
1033 }
1034 }
1035
1036 expected_copy_base(expected_copy_base &&rhs) = default;
1037 expected_copy_base &operator=(const expected_copy_base &rhs) = default;
1038 expected_copy_base &operator=(expected_copy_base &&rhs) = default;
1039};
1040
1041// This class manages conditionally having a trivial move constructor
1042// Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it
1043// doesn't implement an analogue to std::is_trivially_move_constructible. We
1044// have to make do with a non-trivial move constructor even if T is trivially
1045// move constructible
1046#ifndef TL_EXPECTED_GCC49
1047template <class T, class E,
1048 bool = is_void_or<T, std::is_trivially_move_constructible<T>>::value &&
1049 std::is_trivially_move_constructible<E>::value>
1051 using expected_copy_base<T, E>::expected_copy_base;
1052};
1053#else
1054template <class T, class E, bool = false>
1055struct expected_move_base;
1056#endif
1057template <class T, class E>
1058struct expected_move_base<T, E, false> : expected_copy_base<T, E> {
1059 using expected_copy_base<T, E>::expected_copy_base;
1060
1061 expected_move_base() = default;
1062 expected_move_base(const expected_move_base &rhs) = default;
1063
1064 expected_move_base(expected_move_base &&rhs) noexcept(std::is_nothrow_move_constructible<T>::value)
1065 : expected_copy_base<T, E>(no_init)
1066 {
1067 if (rhs.has_value()) {
1068 this->construct_with(std::move(rhs));
1069 } else {
1070 this->construct_error(std::move(rhs.geterr()));
1071 }
1072 }
1073 expected_move_base &operator=(const expected_move_base &rhs) = default;
1074 expected_move_base &operator=(expected_move_base &&rhs) = default;
1075};
1076
1077// This class manages conditionally having a trivial copy assignment operator
1078template <class T, class E,
1079 bool = is_void_or<T, conjunction<TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T),
1080 TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T),
1081 TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T)>>::value &&
1082 TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(E)::value &&
1083 TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value &&
1084 TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(E)::value>
1086 using expected_move_base<T, E>::expected_move_base;
1087};
1088
1089template <class T, class E>
1091 using expected_move_base<T, E>::expected_move_base;
1092
1093 expected_copy_assign_base() = default;
1095
1098 {
1099 this->assign(rhs);
1100 return *this;
1101 }
1102 expected_copy_assign_base &operator=(expected_copy_assign_base &&rhs) = default;
1103};
1104
1105// This class manages conditionally having a trivial move assignment operator
1106// Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it
1107// doesn't implement an analogue to std::is_trivially_move_assignable. We have
1108// to make do with a non-trivial move assignment operator even if T is trivially
1109// move assignable
1110#ifndef TL_EXPECTED_GCC49
1111template <class T, class E,
1112 bool = is_void_or<T, conjunction<std::is_trivially_destructible<T>, std::is_trivially_move_constructible<T>,
1113 std::is_trivially_move_assignable<T>>>::value &&
1114 std::is_trivially_destructible<E>::value && std::is_trivially_move_constructible<E>::value &&
1115 std::is_trivially_move_assignable<E>::value>
1117 using expected_copy_assign_base<T, E>::expected_copy_assign_base;
1118};
1119#else
1120template <class T, class E, bool = false>
1122#endif
1123
1124template <class T, class E>
1126 using expected_copy_assign_base<T, E>::expected_copy_assign_base;
1127
1128 expected_move_assign_base() = default;
1130
1132
1133 expected_move_assign_base &operator=(const expected_move_assign_base &rhs) = default;
1134
1135 expected_move_assign_base &operator=(expected_move_assign_base &&rhs) noexcept(
1136 std::is_nothrow_move_constructible<T>::value && std::is_nothrow_move_assignable<T>::value)
1137 {
1138 this->assign(std::move(rhs));
1139 return *this;
1140 }
1141};
1142
1143// expected_delete_ctor_base will conditionally delete copy and move
1144// constructors depending on whether T is copy/move constructible
1145template <class T, class E,
1146 bool EnableCopy = (is_copy_constructible_or_void<T>::value && std::is_copy_constructible<E>::value),
1147 bool EnableMove = (is_move_constructible_or_void<T>::value && std::is_move_constructible<E>::value)>
1149 expected_delete_ctor_base() = default;
1152 expected_delete_ctor_base &operator=(const expected_delete_ctor_base &) = default;
1153 expected_delete_ctor_base &operator=(expected_delete_ctor_base &&) noexcept = default;
1154};
1155
1156template <class T, class E>
1157struct expected_delete_ctor_base<T, E, true, false> {
1158 expected_delete_ctor_base() = default;
1161 expected_delete_ctor_base &operator=(const expected_delete_ctor_base &) = default;
1162 expected_delete_ctor_base &operator=(expected_delete_ctor_base &&) noexcept = default;
1163};
1164
1165template <class T, class E>
1166struct expected_delete_ctor_base<T, E, false, true> {
1167 expected_delete_ctor_base() = default;
1170 expected_delete_ctor_base &operator=(const expected_delete_ctor_base &) = default;
1171 expected_delete_ctor_base &operator=(expected_delete_ctor_base &&) noexcept = default;
1172};
1173
1174template <class T, class E>
1175struct expected_delete_ctor_base<T, E, false, false> {
1176 expected_delete_ctor_base() = default;
1179 expected_delete_ctor_base &operator=(const expected_delete_ctor_base &) = default;
1180 expected_delete_ctor_base &operator=(expected_delete_ctor_base &&) noexcept = default;
1181};
1182
1183// expected_delete_assign_base will conditionally delete copy and move
1184// constructors depending on whether T and E are copy/move constructible +
1185// assignable
1186template <class T, class E,
1187 bool EnableCopy = (is_copy_constructible_or_void<T>::value && std::is_copy_constructible<E>::value &&
1188 is_copy_assignable_or_void<T>::value && std::is_copy_assignable<E>::value),
1189 bool EnableMove = (is_move_constructible_or_void<T>::value && std::is_move_constructible<E>::value &&
1190 is_move_assignable_or_void<T>::value && std::is_move_assignable<E>::value)>
1198
1199template <class T, class E>
1200struct expected_delete_assign_base<T, E, true, false> {
1201 expected_delete_assign_base() = default;
1204 expected_delete_assign_base &operator=(const expected_delete_assign_base &) = default;
1205 expected_delete_assign_base &operator=(expected_delete_assign_base &&) noexcept = delete;
1206};
1207
1208template <class T, class E>
1209struct expected_delete_assign_base<T, E, false, true> {
1210 expected_delete_assign_base() = default;
1213 expected_delete_assign_base &operator=(const expected_delete_assign_base &) = delete;
1214 expected_delete_assign_base &operator=(expected_delete_assign_base &&) noexcept = default;
1215};
1216
1217template <class T, class E>
1218struct expected_delete_assign_base<T, E, false, false> {
1219 expected_delete_assign_base() = default;
1222 expected_delete_assign_base &operator=(const expected_delete_assign_base &) = delete;
1223 expected_delete_assign_base &operator=(expected_delete_assign_base &&) noexcept = delete;
1224};
1225
1226// This is needed to be able to construct the expected_default_ctor_base which
1227// follows, while still conditionally deleting the default constructor.
1229 explicit constexpr default_constructor_tag() = default;
1230};
1231
1232// expected_default_ctor_base will ensure that expected has a deleted default
1233// consturctor if T is not default constructible.
1234// This specialization is for when T is default constructible
1235template <class T, class E, bool Enable = std::is_default_constructible<T>::value || std::is_void<T>::value>
1237 constexpr expected_default_ctor_base() noexcept = default;
1238 constexpr expected_default_ctor_base(expected_default_ctor_base const &) noexcept = default;
1239 constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept = default;
1240 expected_default_ctor_base &operator=(expected_default_ctor_base const &) noexcept = default;
1241 expected_default_ctor_base &operator=(expected_default_ctor_base &&) noexcept = default;
1242
1244 {
1245 }
1246};
1247
1248// This specialization is for when T is not default constructible
1249template <class T, class E>
1250struct expected_default_ctor_base<T, E, false> {
1251 constexpr expected_default_ctor_base() noexcept = delete;
1252 constexpr expected_default_ctor_base(expected_default_ctor_base const &) noexcept = default;
1253 constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept = default;
1254 expected_default_ctor_base &operator=(expected_default_ctor_base const &) noexcept = default;
1255 expected_default_ctor_base &operator=(expected_default_ctor_base &&) noexcept = default;
1256
1258 {
1259 }
1260};
1261} // namespace detail
1262
1263template <class E>
1264class bad_expected_access : public std::exception {
1265public:
1266 explicit bad_expected_access(E e) : m_val(std::move(e))
1267 {
1268 }
1269
1270 virtual const char *what() const noexcept override
1271 {
1272 return "Bad expected access";
1273 }
1274
1275 const E &error() const &
1276 {
1277 return m_val;
1278 }
1279 E &error() &
1280 {
1281 return m_val;
1282 }
1283 const E &&error() const &&
1284 {
1285 return std::move(m_val);
1286 }
1287 E &&error() &&
1288 {
1289 return std::move(m_val);
1290 }
1291
1292private:
1293 E m_val;
1294};
1295
1303template <class T, class E>
1308 static_assert(!std::is_reference<T>::value, "T must not be a reference");
1309 static_assert(!std::is_same<T, std::remove_cv<in_place_t>::type>::value, "T must not be in_place_t");
1310 static_assert(!std::is_same<T, std::remove_cv<unexpect_t>::type>::value, "T must not be unexpect_t");
1311 static_assert(!std::is_same<T, typename std::remove_cv<unexpected<E>>::type>::value, "T must not be unexpected<E>");
1312 static_assert(!std::is_reference<E>::value, "E must not be a reference");
1313
1314 T *valptr()
1315 {
1316 return std::addressof(this->m_val);
1317 }
1318 const T *valptr() const
1319 {
1320 return std::addressof(this->m_val);
1321 }
1322 unexpected<E> *errptr()
1323 {
1324 return std::addressof(this->m_unexpect);
1325 }
1326 const unexpected<E> *errptr() const
1327 {
1328 return std::addressof(this->m_unexpect);
1329 }
1330
1331 template <class U = T, detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
1332 TL_EXPECTED_11_CONSTEXPR U &val()
1333 {
1334 return this->m_val;
1335 }
1336 TL_EXPECTED_11_CONSTEXPR unexpected<E> &err()
1337 {
1338 return this->m_unexpect;
1339 }
1340
1341 template <class U = T, detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
1342 constexpr const U &val() const
1343 {
1344 return this->m_val;
1345 }
1346 constexpr const unexpected<E> &err() const
1347 {
1348 return this->m_unexpect;
1349 }
1350
1353
1354public:
1355 typedef T value_type;
1356 typedef E error_type;
1358
1359#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && !defined(TL_EXPECTED_GCC54) && \
1360 !defined(TL_EXPECTED_GCC55)
1361 template <class F>
1362 TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) &
1363 {
1364 return and_then_impl(*this, std::forward<F>(f));
1365 }
1366 template <class F>
1367 TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) &&
1368 {
1369 return and_then_impl(std::move(*this), std::forward<F>(f));
1370 }
1371 template <class F>
1372 constexpr auto and_then(F &&f) const &
1373 {
1374 return and_then_impl(*this, std::forward<F>(f));
1375 }
1376
1377#ifndef TL_EXPECTED_NO_CONSTRR
1378 template <class F>
1379 constexpr auto and_then(F &&f) const &&
1380 {
1381 return and_then_impl(std::move(*this), std::forward<F>(f));
1382 }
1383#endif
1384
1385#else
1386 template <class F>
1387 TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) & -> decltype(and_then_impl(std::declval<expected &>(),
1388 std::forward<F>(f)))
1389 {
1390 return and_then_impl(*this, std::forward<F>(f));
1391 }
1392 template <class F>
1393 TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) && -> decltype(and_then_impl(std::declval<expected &&>(),
1394 std::forward<F>(f)))
1395 {
1396 return and_then_impl(std::move(*this), std::forward<F>(f));
1397 }
1398 template <class F>
1399 constexpr auto and_then(F &&f) const & -> decltype(and_then_impl(std::declval<expected const &>(),
1400 std::forward<F>(f)))
1401 {
1402 return and_then_impl(*this, std::forward<F>(f));
1403 }
1404
1405#ifndef TL_EXPECTED_NO_CONSTRR
1406 template <class F>
1407 constexpr auto and_then(F &&f) const && -> decltype(and_then_impl(std::declval<expected const &&>(),
1408 std::forward<F>(f)))
1409 {
1410 return and_then_impl(std::move(*this), std::forward<F>(f));
1411 }
1412#endif
1413#endif
1414
1415#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && !defined(TL_EXPECTED_GCC54) && \
1416 !defined(TL_EXPECTED_GCC55)
1417 template <class F>
1418 TL_EXPECTED_11_CONSTEXPR auto map(F &&f) &
1419 {
1420 return expected_map_impl(*this, std::forward<F>(f));
1421 }
1422 template <class F>
1423 TL_EXPECTED_11_CONSTEXPR auto map(F &&f) &&
1424 {
1425 return expected_map_impl(std::move(*this), std::forward<F>(f));
1426 }
1427 template <class F>
1428 constexpr auto map(F &&f) const &
1429 {
1430 return expected_map_impl(*this, std::forward<F>(f));
1431 }
1432 template <class F>
1433 constexpr auto map(F &&f) const &&
1434 {
1435 return expected_map_impl(std::move(*this), std::forward<F>(f));
1436 }
1437#else
1438 template <class F>
1439 TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval<expected &>(), std::declval<F &&>())) map(F &&f) &
1440 {
1441 return expected_map_impl(*this, std::forward<F>(f));
1442 }
1443 template <class F>
1444 TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval<expected>(), std::declval<F &&>())) map(F &&f) &&
1445 {
1446 return expected_map_impl(std::move(*this), std::forward<F>(f));
1447 }
1448 template <class F>
1449 constexpr decltype(expected_map_impl(std::declval<const expected &>(), std::declval<F &&>())) map(F &&f) const &
1450 {
1451 return expected_map_impl(*this, std::forward<F>(f));
1452 }
1453
1454#ifndef TL_EXPECTED_NO_CONSTRR
1455 template <class F>
1456 constexpr decltype(expected_map_impl(std::declval<const expected &&>(), std::declval<F &&>())) map(F &&f) const &&
1457 {
1458 return expected_map_impl(std::move(*this), std::forward<F>(f));
1459 }
1460#endif
1461#endif
1462
1463#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && !defined(TL_EXPECTED_GCC54) && \
1464 !defined(TL_EXPECTED_GCC55)
1465 template <class F>
1466 TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) &
1467 {
1468 return expected_map_impl(*this, std::forward<F>(f));
1469 }
1470 template <class F>
1471 TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) &&
1472 {
1473 return expected_map_impl(std::move(*this), std::forward<F>(f));
1474 }
1475 template <class F>
1476 constexpr auto transform(F &&f) const &
1477 {
1478 return expected_map_impl(*this, std::forward<F>(f));
1479 }
1480 template <class F>
1481 constexpr auto transform(F &&f) const &&
1482 {
1483 return expected_map_impl(std::move(*this), std::forward<F>(f));
1484 }
1485#else
1486 template <class F>
1487 TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval<expected &>(), std::declval<F &&>())) transform(
1488 F &&f) &
1489 {
1490 return expected_map_impl(*this, std::forward<F>(f));
1491 }
1492 template <class F>
1493 TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval<expected>(), std::declval<F &&>())) transform(
1494 F &&f) &&
1495 {
1496 return expected_map_impl(std::move(*this), std::forward<F>(f));
1497 }
1498 template <class F>
1499 constexpr decltype(expected_map_impl(std::declval<const expected &>(), std::declval<F &&>())) transform(
1500 F &&f) const &
1501 {
1502 return expected_map_impl(*this, std::forward<F>(f));
1503 }
1504
1505#ifndef TL_EXPECTED_NO_CONSTRR
1506 template <class F>
1507 constexpr decltype(expected_map_impl(std::declval<const expected &&>(), std::declval<F &&>())) transform(
1508 F &&f) const &&
1509 {
1510 return expected_map_impl(std::move(*this), std::forward<F>(f));
1511 }
1512#endif
1513#endif
1514
1515#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && !defined(TL_EXPECTED_GCC54) && \
1516 !defined(TL_EXPECTED_GCC55)
1517 template <class F>
1518 TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) &
1519 {
1520 return map_error_impl(*this, std::forward<F>(f));
1521 }
1522 template <class F>
1523 TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) &&
1524 {
1525 return map_error_impl(std::move(*this), std::forward<F>(f));
1526 }
1527 template <class F>
1528 constexpr auto map_error(F &&f) const &
1529 {
1530 return map_error_impl(*this, std::forward<F>(f));
1531 }
1532 template <class F>
1533 constexpr auto map_error(F &&f) const &&
1534 {
1535 return map_error_impl(std::move(*this), std::forward<F>(f));
1536 }
1537#else
1538 template <class F>
1539 TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &>(), std::declval<F &&>())) map_error(
1540 F &&f) &
1541 {
1542 return map_error_impl(*this, std::forward<F>(f));
1543 }
1544 template <class F>
1545 TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &&>(), std::declval<F &&>())) map_error(
1546 F &&f) &&
1547 {
1548 return map_error_impl(std::move(*this), std::forward<F>(f));
1549 }
1550 template <class F>
1551 constexpr decltype(map_error_impl(std::declval<const expected &>(), std::declval<F &&>())) map_error(F &&f) const &
1552 {
1553 return map_error_impl(*this, std::forward<F>(f));
1554 }
1555
1556#ifndef TL_EXPECTED_NO_CONSTRR
1557 template <class F>
1558 constexpr decltype(map_error_impl(std::declval<const expected &&>(), std::declval<F &&>())) map_error(
1559 F &&f) const &&
1560 {
1561 return map_error_impl(std::move(*this), std::forward<F>(f));
1562 }
1563#endif
1564#endif
1565#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && !defined(TL_EXPECTED_GCC54) && \
1566 !defined(TL_EXPECTED_GCC55)
1567 template <class F>
1568 TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) &
1569 {
1570 return map_error_impl(*this, std::forward<F>(f));
1571 }
1572 template <class F>
1573 TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) &&
1574 {
1575 return map_error_impl(std::move(*this), std::forward<F>(f));
1576 }
1577 template <class F>
1578 constexpr auto transform_error(F &&f) const &
1579 {
1580 return map_error_impl(*this, std::forward<F>(f));
1581 }
1582 template <class F>
1583 constexpr auto transform_error(F &&f) const &&
1584 {
1585 return map_error_impl(std::move(*this), std::forward<F>(f));
1586 }
1587#else
1588 template <class F>
1589 TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &>(), std::declval<F &&>())) transform_error(
1590 F &&f) &
1591 {
1592 return map_error_impl(*this, std::forward<F>(f));
1593 }
1594 template <class F>
1595 TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &&>(), std::declval<F &&>()))
1596 transform_error(F &&f) &&
1597 {
1598 return map_error_impl(std::move(*this), std::forward<F>(f));
1599 }
1600 template <class F>
1601 constexpr decltype(map_error_impl(std::declval<const expected &>(), std::declval<F &&>())) transform_error(
1602 F &&f) const &
1603 {
1604 return map_error_impl(*this, std::forward<F>(f));
1605 }
1606
1607#ifndef TL_EXPECTED_NO_CONSTRR
1608 template <class F>
1609 constexpr decltype(map_error_impl(std::declval<const expected &&>(), std::declval<F &&>())) transform_error(
1610 F &&f) const &&
1611 {
1612 return map_error_impl(std::move(*this), std::forward<F>(f));
1613 }
1614#endif
1615#endif
1616 template <class F>
1617 expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) &
1618 {
1619 return or_else_impl(*this, std::forward<F>(f));
1620 }
1621
1622 template <class F>
1623 expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) &&
1624 {
1625 return or_else_impl(std::move(*this), std::forward<F>(f));
1626 }
1627
1628 template <class F>
1629 expected constexpr or_else(F &&f) const &
1630 {
1631 return or_else_impl(*this, std::forward<F>(f));
1632 }
1633
1634#ifndef TL_EXPECTED_NO_CONSTRR
1635 template <class F>
1636 expected constexpr or_else(F &&f) const &&
1637 {
1638 return or_else_impl(std::move(*this), std::forward<F>(f));
1639 }
1640#endif
1641 constexpr expected() = default;
1642 constexpr expected(const expected &rhs) = default;
1643 constexpr expected(expected &&rhs) = default;
1644 expected &operator=(const expected &rhs) = default;
1645 expected &operator=(expected &&rhs) = default;
1646
1647 template <class... Args, detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * = nullptr>
1648 constexpr expected(in_place_t, Args &&...args)
1649 : impl_base(in_place, std::forward<Args>(args)...), ctor_base(detail::default_constructor_tag{})
1650 {
1651 }
1652
1653 template <class U, class... Args,
1654 detail::enable_if_t<std::is_constructible<T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
1655 constexpr expected(in_place_t, std::initializer_list<U> il, Args &&...args)
1656 : impl_base(in_place, il, std::forward<Args>(args)...), ctor_base(detail::default_constructor_tag{})
1657 {
1658 }
1659
1660 template <class G = E, detail::enable_if_t<std::is_constructible<E, const G &>::value> * = nullptr,
1661 detail::enable_if_t<!std::is_convertible<const G &, E>::value> * = nullptr>
1662 explicit constexpr expected(const unexpected<G> &e)
1663 : impl_base(unexpect, e.value()), ctor_base(detail::default_constructor_tag{})
1664 {
1665 }
1666
1667 template <class G = E, detail::enable_if_t<std::is_constructible<E, const G &>::value> * = nullptr,
1668 detail::enable_if_t<std::is_convertible<const G &, E>::value> * = nullptr>
1669 constexpr expected(unexpected<G> const &e)
1670 : impl_base(unexpect, e.value()), ctor_base(detail::default_constructor_tag{})
1671 {
1672 }
1673
1674 template <class G = E, detail::enable_if_t<std::is_constructible<E, G &&>::value> * = nullptr,
1675 detail::enable_if_t<!std::is_convertible<G &&, E>::value> * = nullptr>
1676 explicit constexpr expected(unexpected<G> &&e) noexcept(std::is_nothrow_constructible<E, G &&>::value)
1677 : impl_base(unexpect, std::move(e.value())), ctor_base(detail::default_constructor_tag{})
1678 {
1679 }
1680
1681 template <class G = E, detail::enable_if_t<std::is_constructible<E, G &&>::value> * = nullptr,
1682 detail::enable_if_t<std::is_convertible<G &&, E>::value> * = nullptr>
1683 constexpr expected(unexpected<G> &&e) noexcept(std::is_nothrow_constructible<E, G &&>::value)
1684 : impl_base(unexpect, std::move(e.value())), ctor_base(detail::default_constructor_tag{})
1685 {
1686 }
1687
1688 template <class... Args, detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * = nullptr>
1689 constexpr explicit expected(unexpect_t, Args &&...args)
1690 : impl_base(unexpect, std::forward<Args>(args)...), ctor_base(detail::default_constructor_tag{})
1691 {
1692 }
1693
1694 template <class U, class... Args,
1695 detail::enable_if_t<std::is_constructible<E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
1696 constexpr explicit expected(unexpect_t, std::initializer_list<U> il, Args &&...args)
1697 : impl_base(unexpect, il, std::forward<Args>(args)...), ctor_base(detail::default_constructor_tag{})
1698 {
1699 }
1700
1701 template <class U, class G,
1702 detail::enable_if_t<!(std::is_convertible<U const &, T>::value &&
1703 std::is_convertible<G const &, E>::value)> * = nullptr,
1704 detail::expected_enable_from_other<T, E, U, G, const U &, const G &> * = nullptr>
1705 explicit TL_EXPECTED_11_CONSTEXPR expected(const expected<U, G> &rhs) : ctor_base(detail::default_constructor_tag{})
1706 {
1707 if (rhs.has_value()) {
1708 this->construct(*rhs);
1709 } else {
1710 this->construct_error(rhs.error());
1711 }
1712 }
1713
1714 template <class U, class G,
1715 detail::enable_if_t<(std::is_convertible<U const &, T>::value &&
1716 std::is_convertible<G const &, E>::value)> * = nullptr,
1717 detail::expected_enable_from_other<T, E, U, G, const U &, const G &> * = nullptr>
1718 TL_EXPECTED_11_CONSTEXPR expected(const expected<U, G> &rhs) : ctor_base(detail::default_constructor_tag{})
1719 {
1720 if (rhs.has_value()) {
1721 this->construct(*rhs);
1722 } else {
1723 this->construct_error(rhs.error());
1724 }
1725 }
1726
1727 template <
1728 class U, class G,
1729 detail::enable_if_t<!(std::is_convertible<U &&, T>::value && std::is_convertible<G &&, E>::value)> * = nullptr,
1730 detail::expected_enable_from_other<T, E, U, G, U &&, G &&> * = nullptr>
1731 explicit TL_EXPECTED_11_CONSTEXPR expected(expected<U, G> &&rhs) : ctor_base(detail::default_constructor_tag{})
1732 {
1733 if (rhs.has_value()) {
1734 this->construct(std::move(*rhs));
1735 } else {
1736 this->construct_error(std::move(rhs.error()));
1737 }
1738 }
1739
1740 template <
1741 class U, class G,
1742 detail::enable_if_t<(std::is_convertible<U &&, T>::value && std::is_convertible<G &&, E>::value)> * = nullptr,
1743 detail::expected_enable_from_other<T, E, U, G, U &&, G &&> * = nullptr>
1744 TL_EXPECTED_11_CONSTEXPR expected(expected<U, G> &&rhs) : ctor_base(detail::default_constructor_tag{})
1745 {
1746 if (rhs.has_value()) {
1747 this->construct(std::move(*rhs));
1748 } else {
1749 this->construct_error(std::move(rhs.error()));
1750 }
1751 }
1752
1753 template <class U = T, detail::enable_if_t<!std::is_convertible<U &&, T>::value> * = nullptr,
1754 detail::expected_enable_forward_value<T, E, U> * = nullptr>
1755 explicit TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v) : expected(in_place, std::forward<U>(v))
1756 {
1757 }
1758
1759 template <class U = T, detail::enable_if_t<std::is_convertible<U &&, T>::value> * = nullptr,
1760 detail::expected_enable_forward_value<T, E, U> * = nullptr>
1761 TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v) : expected(in_place, std::forward<U>(v))
1762 {
1763 }
1764
1765 template <
1766 class U = T, class G = T, detail::enable_if_t<std::is_nothrow_constructible<T, U &&>::value> * = nullptr,
1767 detail::enable_if_t<!std::is_void<G>::value> * = nullptr,
1768 detail::enable_if_t<(!std::is_same<expected<T, E>, detail::decay_t<U>>::value &&
1769 !detail::conjunction<std::is_scalar<T>, std::is_same<T, detail::decay_t<U>>>::value &&
1770 std::is_constructible<T, U>::value && std::is_assignable<G &, U>::value &&
1771 std::is_nothrow_move_constructible<E>::value)> * = nullptr>
1772 expected &operator=(U &&v)
1773 {
1774 if (has_value()) {
1775 val() = std::forward<U>(v);
1776 } else {
1777 err().~unexpected<E>();
1778 ::new (valptr()) T(std::forward<U>(v));
1779 this->m_has_val = true;
1780 }
1781
1782 return *this;
1783 }
1784
1785 template <
1786 class U = T, class G = T, detail::enable_if_t<!std::is_nothrow_constructible<T, U &&>::value> * = nullptr,
1787 detail::enable_if_t<!std::is_void<U>::value> * = nullptr,
1788 detail::enable_if_t<(!std::is_same<expected<T, E>, detail::decay_t<U>>::value &&
1789 !detail::conjunction<std::is_scalar<T>, std::is_same<T, detail::decay_t<U>>>::value &&
1790 std::is_constructible<T, U>::value && std::is_assignable<G &, U>::value &&
1791 std::is_nothrow_move_constructible<E>::value)> * = nullptr>
1792 expected &operator=(U &&v)
1793 {
1794 if (has_value()) {
1795 val() = std::forward<U>(v);
1796 } else {
1797 auto tmp = std::move(err());
1798 err().~unexpected<E>();
1799
1800#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
1801 try {
1802 ::new (valptr()) T(std::forward<U>(v));
1803 this->m_has_val = true;
1804 } catch (...) {
1805 err() = std::move(tmp);
1806 throw;
1807 }
1808#else
1809 ::new (valptr()) T(std::forward<U>(v));
1810 this->m_has_val = true;
1811#endif
1812 }
1813
1814 return *this;
1815 }
1816
1817 template <class G = E, detail::enable_if_t<std::is_nothrow_copy_constructible<G>::value &&
1818 std::is_assignable<G &, G>::value> * = nullptr>
1819 expected &operator=(const unexpected<G> &rhs)
1820 {
1821 if (!has_value()) {
1822 err() = rhs;
1823 } else {
1824 this->destroy_val();
1825 ::new (errptr()) unexpected<E>(rhs);
1826 this->m_has_val = false;
1827 }
1828
1829 return *this;
1830 }
1831
1832 template <class G = E, detail::enable_if_t<std::is_nothrow_move_constructible<G>::value &&
1833 std::is_move_assignable<G>::value> * = nullptr>
1834 expected &operator=(unexpected<G> &&rhs) noexcept
1835 {
1836 if (!has_value()) {
1837 err() = std::move(rhs);
1838 } else {
1839 this->destroy_val();
1840 ::new (errptr()) unexpected<E>(std::move(rhs));
1841 this->m_has_val = false;
1842 }
1843
1844 return *this;
1845 }
1846
1847 template <class... Args, detail::enable_if_t<std::is_nothrow_constructible<T, Args &&...>::value> * = nullptr>
1848 void emplace(Args &&...args)
1849 {
1850 if (has_value()) {
1851 val().~T();
1852 } else {
1853 err().~unexpected<E>();
1854 this->m_has_val = true;
1855 }
1856 ::new (valptr()) T(std::forward<Args>(args)...);
1857 }
1858
1859 template <class... Args, detail::enable_if_t<!std::is_nothrow_constructible<T, Args &&...>::value> * = nullptr>
1860 void emplace(Args &&...args)
1861 {
1862 if (has_value()) {
1863 val().~T();
1864 ::new (valptr()) T(std::forward<Args>(args)...);
1865 } else {
1866 auto tmp = std::move(err());
1867 err().~unexpected<E>();
1868
1869#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
1870 try {
1871 ::new (valptr()) T(std::forward<Args>(args)...);
1872 this->m_has_val = true;
1873 } catch (...) {
1874 err() = std::move(tmp);
1875 throw;
1876 }
1877#else
1878 ::new (valptr()) T(std::forward<Args>(args)...);
1879 this->m_has_val = true;
1880#endif
1881 }
1882 }
1883
1884 template <class U, class... Args,
1885 detail::enable_if_t<std::is_nothrow_constructible<T, std::initializer_list<U> &, Args &&...>::value> * =
1886 nullptr>
1887 void emplace(std::initializer_list<U> il, Args &&...args)
1888 {
1889 if (has_value()) {
1890 T t(il, std::forward<Args>(args)...);
1891 val() = std::move(t);
1892 } else {
1893 err().~unexpected<E>();
1894 ::new (valptr()) T(il, std::forward<Args>(args)...);
1895 this->m_has_val = true;
1896 }
1897 }
1898
1899 template <class U, class... Args,
1900 detail::enable_if_t<!std::is_nothrow_constructible<T, std::initializer_list<U> &, Args &&...>::value> * =
1901 nullptr>
1902 void emplace(std::initializer_list<U> il, Args &&...args)
1903 {
1904 if (has_value()) {
1905 T t(il, std::forward<Args>(args)...);
1906 val() = std::move(t);
1907 } else {
1908 auto tmp = std::move(err());
1909 err().~unexpected<E>();
1910
1911#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
1912 try {
1913 ::new (valptr()) T(il, std::forward<Args>(args)...);
1914 this->m_has_val = true;
1915 } catch (...) {
1916 err() = std::move(tmp);
1917 throw;
1918 }
1919#else
1920 ::new (valptr()) T(il, std::forward<Args>(args)...);
1921 this->m_has_val = true;
1922#endif
1923 }
1924 }
1925
1926private:
1927 using t_is_void = std::true_type;
1928 using t_is_not_void = std::false_type;
1929 using t_is_nothrow_move_constructible = std::true_type;
1930 using move_constructing_t_can_throw = std::false_type;
1931 using e_is_nothrow_move_constructible = std::true_type;
1932 using move_constructing_e_can_throw = std::false_type;
1933
1934 void swap_where_both_have_value(expected & /*rhs*/, t_is_void) noexcept
1935 {
1936 // swapping void is a no-op
1937 }
1938
1939 void swap_where_both_have_value(expected &rhs, t_is_not_void)
1940 {
1941 using std::swap;
1942 swap(val(), rhs.val());
1943 }
1944
1945 void swap_where_only_one_has_value(expected &rhs, t_is_void) noexcept(std::is_nothrow_move_constructible<E>::value)
1946 {
1947 ::new (errptr()) unexpected_type(std::move(rhs.err()));
1948 rhs.err().~unexpected_type();
1949 std::swap(this->m_has_val, rhs.m_has_val);
1950 }
1951
1952 void swap_where_only_one_has_value(expected &rhs, t_is_not_void)
1953 {
1954 swap_where_only_one_has_value_and_t_is_not_void(rhs, typename std::is_nothrow_move_constructible<T>::type{},
1955 typename std::is_nothrow_move_constructible<E>::type{});
1956 }
1957
1958 void swap_where_only_one_has_value_and_t_is_not_void(expected &rhs, t_is_nothrow_move_constructible,
1959 e_is_nothrow_move_constructible) noexcept
1960 {
1961 auto temp = std::move(val());
1962 val().~T();
1963 ::new (errptr()) unexpected_type(std::move(rhs.err()));
1964 rhs.err().~unexpected_type();
1965 ::new (rhs.valptr()) T(std::move(temp));
1966 std::swap(this->m_has_val, rhs.m_has_val);
1967 }
1968
1969 void swap_where_only_one_has_value_and_t_is_not_void(expected &rhs, t_is_nothrow_move_constructible,
1970 move_constructing_e_can_throw)
1971 {
1972 auto temp = std::move(val());
1973 val().~T();
1974#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
1975 try {
1976 ::new (errptr()) unexpected_type(std::move(rhs.err()));
1977 rhs.err().~unexpected_type();
1978 ::new (rhs.valptr()) T(std::move(temp));
1979 std::swap(this->m_has_val, rhs.m_has_val);
1980 } catch (...) {
1981 val() = std::move(temp);
1982 throw;
1983 }
1984#else
1985 ::new (errptr()) unexpected_type(std::move(rhs.err()));
1986 rhs.err().~unexpected_type();
1987 ::new (rhs.valptr()) T(std::move(temp));
1988 std::swap(this->m_has_val, rhs.m_has_val);
1989#endif
1990 }
1991
1992 void swap_where_only_one_has_value_and_t_is_not_void(expected &rhs, move_constructing_t_can_throw,
1993 e_is_nothrow_move_constructible)
1994 {
1995 auto temp = std::move(rhs.err());
1996 rhs.err().~unexpected_type();
1997#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
1998 try {
1999 ::new (rhs.valptr()) T(std::move(val()));
2000 val().~T();
2001 ::new (errptr()) unexpected_type(std::move(temp));
2002 std::swap(this->m_has_val, rhs.m_has_val);
2003 } catch (...) {
2004 rhs.err() = std::move(temp);
2005 throw;
2006 }
2007#else
2008 ::new (rhs.valptr()) T(std::move(val()));
2009 val().~T();
2010 ::new (errptr()) unexpected_type(std::move(temp));
2011 std::swap(this->m_has_val, rhs.m_has_val);
2012#endif
2013 }
2014
2015public:
2016 template <class OT = T, class OE = E>
2017 detail::enable_if_t<detail::is_swappable<OT>::value && detail::is_swappable<OE>::value &&
2018 (std::is_nothrow_move_constructible<OT>::value ||
2019 std::is_nothrow_move_constructible<OE>::value)>
2020 swap(expected &rhs) noexcept(std::is_nothrow_move_constructible<T>::value &&
2022 std::is_nothrow_move_constructible<E>::value && detail::is_nothrow_swappable<E>::value)
2023 {
2024 if (has_value() && rhs.has_value()) {
2025 swap_where_both_have_value(rhs, typename std::is_void<T>::type{});
2026 } else if (!has_value() && rhs.has_value()) {
2027 rhs.swap(*this);
2028 } else if (has_value()) {
2029 swap_where_only_one_has_value(rhs, typename std::is_void<T>::type{});
2030 } else {
2031 using std::swap;
2032 swap(err(), rhs.err());
2033 }
2034 }
2035
2036 constexpr const T *operator->() const
2037 {
2038 TL_ASSERT(has_value());
2039 return valptr();
2040 }
2041 TL_EXPECTED_11_CONSTEXPR T *operator->()
2042 {
2043 TL_ASSERT(has_value());
2044 return valptr();
2045 }
2046
2047 template <class U = T, detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
2048 constexpr const U &operator*() const &
2049 {
2050 TL_ASSERT(has_value());
2051 return val();
2052 }
2053 template <class U = T, detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
2054 TL_EXPECTED_11_CONSTEXPR U &operator*() &
2055 {
2056 TL_ASSERT(has_value());
2057 return val();
2058 }
2059 template <class U = T, detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
2060 constexpr const U &&operator*() const &&
2061 {
2062 TL_ASSERT(has_value());
2063 return std::move(val());
2064 }
2065 template <class U = T, detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
2066 TL_EXPECTED_11_CONSTEXPR U &&operator*() &&
2067 {
2068 TL_ASSERT(has_value());
2069 return std::move(val());
2070 }
2071 constexpr bool has_value() const noexcept
2072 {
2073 return this->m_has_val;
2074 }
2075 constexpr bool has_error() const noexcept
2076 {
2077 return !(this->has_value());
2078 } // Add by M5Stack
2079 constexpr explicit operator bool() const noexcept
2080 {
2081 return this->m_has_val;
2082 }
2083
2084 template <class U = T, detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
2085 TL_EXPECTED_11_CONSTEXPR const U &value() const &
2086 {
2087 if (!has_value()) detail::throw_exception(bad_expected_access<E>(err().value()));
2088 return val();
2089 }
2090 template <class U = T, detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
2091 TL_EXPECTED_11_CONSTEXPR U &value() &
2092 {
2093 if (!has_value()) detail::throw_exception(bad_expected_access<E>(err().value()));
2094 return val();
2095 }
2096 template <class U = T, detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
2097 TL_EXPECTED_11_CONSTEXPR const U &&value() const &&
2098 {
2099 if (!has_value()) detail::throw_exception(bad_expected_access<E>(std::move(err()).value()));
2100 return std::move(val());
2101 }
2102 template <class U = T, detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
2103 TL_EXPECTED_11_CONSTEXPR U &&value() &&
2104 {
2105 if (!has_value()) detail::throw_exception(bad_expected_access<E>(std::move(err()).value()));
2106 return std::move(val());
2107 }
2108
2109 constexpr const E &error() const &
2110 {
2111 TL_ASSERT(!has_value());
2112 return err().value();
2113 }
2114 TL_EXPECTED_11_CONSTEXPR E &error() &
2115 {
2116 TL_ASSERT(!has_value());
2117 return err().value();
2118 }
2119 constexpr const E &&error() const &&
2120 {
2121 TL_ASSERT(!has_value());
2122 return std::move(err().value());
2123 }
2124 TL_EXPECTED_11_CONSTEXPR E &&error() &&
2125 {
2126 TL_ASSERT(!has_value());
2127 return std::move(err().value());
2128 }
2129
2130 template <class U>
2131 constexpr T value_or(U &&v) const &
2132 {
2133 static_assert(std::is_copy_constructible<T>::value && std::is_convertible<U &&, T>::value,
2134 "T must be copy-constructible and convertible to from U&&");
2135 return bool(*this) ? **this : static_cast<T>(std::forward<U>(v));
2136 }
2137 template <class U>
2138 TL_EXPECTED_11_CONSTEXPR T value_or(U &&v) &&
2139 {
2140 static_assert(std::is_move_constructible<T>::value && std::is_convertible<U &&, T>::value,
2141 "T must be move-constructible and convertible to from U&&");
2142 return bool(*this) ? std::move(**this) : static_cast<T>(std::forward<U>(v));
2143 }
2144
2145 // Add by M5Stack
2146 template <class G = E>
2147 constexpr E error_or(G &&e) const &
2148 {
2149 static_assert(std::is_copy_constructible<E>::value && std::is_convertible<G, E>::value,
2150 "E must be copy-constructible and convertible to from G&&");
2151 return has_value() ? std::forward<G>(e) : error();
2152 }
2153 template <class G = E>
2154 TL_EXPECTED_11_CONSTEXPR E error_or(G &&e) &&
2155 {
2156 static_assert(std::is_move_constructible<E>::value && std::is_convertible<G, E>::value,
2157 "E must be move-constructible and convertible to from G&&");
2158 return has_value() ? std::forward<G>(e) : std::move(error());
2159 }
2160};
2161
2162namespace detail {
2163template <class Exp>
2164using exp_t = typename detail::decay_t<Exp>::value_type;
2165template <class Exp>
2166using err_t = typename detail::decay_t<Exp>::error_type;
2167template <class Exp, class Ret>
2168using ret_t = expected<Ret, err_t<Exp>>;
2169
2170#ifdef TL_EXPECTED_CXX14
2171template <class Exp, class F, detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
2172 class Ret = decltype(detail::invoke(std::declval<F>(), *std::declval<Exp>()))>
2173constexpr auto and_then_impl(Exp &&exp, F &&f)
2174{
2175 static_assert(detail::is_expected<Ret>::value, "F must return an expected");
2176
2177 return exp.has_value() ? detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp))
2178 : Ret(unexpect, std::forward<Exp>(exp).error());
2179}
2180
2181template <class Exp, class F, detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
2182 class Ret = decltype(detail::invoke(std::declval<F>()))>
2183constexpr auto and_then_impl(Exp &&exp, F &&f)
2184{
2185 static_assert(detail::is_expected<Ret>::value, "F must return an expected");
2186
2187 return exp.has_value() ? detail::invoke(std::forward<F>(f)) : Ret(unexpect, std::forward<Exp>(exp).error());
2188}
2189#else
2190template <class>
2191struct TC;
2192template <class Exp, class F, class Ret = decltype(detail::invoke(std::declval<F>(), *std::declval<Exp>())),
2193 detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr>
2194auto and_then_impl(Exp &&exp, F &&f) -> Ret
2195{
2196 static_assert(detail::is_expected<Ret>::value, "F must return an expected");
2197
2198 return exp.has_value() ? detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp))
2199 : Ret(unexpect, std::forward<Exp>(exp).error());
2200}
2201
2202template <class Exp, class F, class Ret = decltype(detail::invoke(std::declval<F>())),
2203 detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr>
2204constexpr auto and_then_impl(Exp &&exp, F &&f) -> Ret
2205{
2206 static_assert(detail::is_expected<Ret>::value, "F must return an expected");
2207
2208 return exp.has_value() ? detail::invoke(std::forward<F>(f)) : Ret(unexpect, std::forward<Exp>(exp).error());
2209}
2210#endif
2211
2212#ifdef TL_EXPECTED_CXX14
2213template <class Exp, class F, detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
2214 class Ret = decltype(detail::invoke(std::declval<F>(), *std::declval<Exp>())),
2215 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2216constexpr auto expected_map_impl(Exp &&exp, F &&f)
2217{
2218 using result = ret_t<Exp, detail::decay_t<Ret>>;
2219 return exp.has_value() ? result(detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp)))
2220 : result(unexpect, std::forward<Exp>(exp).error());
2221}
2222
2223template <class Exp, class F, detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
2224 class Ret = decltype(detail::invoke(std::declval<F>(), *std::declval<Exp>())),
2225 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2226auto expected_map_impl(Exp &&exp, F &&f)
2227{
2228 using result = expected<void, err_t<Exp>>;
2229 if (exp.has_value()) {
2230 detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp));
2231 return result();
2232 }
2233
2234 return result(unexpect, std::forward<Exp>(exp).error());
2235}
2236
2237template <class Exp, class F, detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
2238 class Ret = decltype(detail::invoke(std::declval<F>())),
2239 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2240constexpr auto expected_map_impl(Exp &&exp, F &&f)
2241{
2242 using result = ret_t<Exp, detail::decay_t<Ret>>;
2243 return exp.has_value() ? result(detail::invoke(std::forward<F>(f)))
2244 : result(unexpect, std::forward<Exp>(exp).error());
2245}
2246
2247template <class Exp, class F, detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
2248 class Ret = decltype(detail::invoke(std::declval<F>())),
2249 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2250auto expected_map_impl(Exp &&exp, F &&f)
2251{
2252 using result = expected<void, err_t<Exp>>;
2253 if (exp.has_value()) {
2254 detail::invoke(std::forward<F>(f));
2255 return result();
2256 }
2257
2258 return result(unexpect, std::forward<Exp>(exp).error());
2259}
2260#else
2261template <class Exp, class F, detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
2262 class Ret = decltype(detail::invoke(std::declval<F>(), *std::declval<Exp>())),
2263 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2264
2265constexpr auto expected_map_impl(Exp &&exp, F &&f) -> ret_t<Exp, detail::decay_t<Ret>>
2266{
2267 using result = ret_t<Exp, detail::decay_t<Ret>>;
2268
2269 return exp.has_value() ? result(detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp)))
2270 : result(unexpect, std::forward<Exp>(exp).error());
2271}
2272
2273template <class Exp, class F, detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
2274 class Ret = decltype(detail::invoke(std::declval<F>(), *std::declval<Exp>())),
2275 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2276
2277auto expected_map_impl(Exp &&exp, F &&f) -> expected<void, err_t<Exp>>
2278{
2279 if (exp.has_value()) {
2280 detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp));
2281 return {};
2282 }
2283
2284 return unexpected<err_t<Exp>>(std::forward<Exp>(exp).error());
2285}
2286
2287template <class Exp, class F, detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
2288 class Ret = decltype(detail::invoke(std::declval<F>())),
2289 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2290
2291constexpr auto expected_map_impl(Exp &&exp, F &&f) -> ret_t<Exp, detail::decay_t<Ret>>
2292{
2293 using result = ret_t<Exp, detail::decay_t<Ret>>;
2294
2295 return exp.has_value() ? result(detail::invoke(std::forward<F>(f)))
2296 : result(unexpect, std::forward<Exp>(exp).error());
2297}
2298
2299template <class Exp, class F, detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
2300 class Ret = decltype(detail::invoke(std::declval<F>())),
2301 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2302
2303auto expected_map_impl(Exp &&exp, F &&f) -> expected<void, err_t<Exp>>
2304{
2305 if (exp.has_value()) {
2306 detail::invoke(std::forward<F>(f));
2307 return {};
2308 }
2309
2310 return unexpected<err_t<Exp>>(std::forward<Exp>(exp).error());
2311}
2312#endif
2313
2314#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && !defined(TL_EXPECTED_GCC54) && \
2315 !defined(TL_EXPECTED_GCC55)
2316template <class Exp, class F, detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
2317 class Ret = decltype(detail::invoke(std::declval<F>(), std::declval<Exp>().error())),
2318 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2319constexpr auto map_error_impl(Exp &&exp, F &&f)
2320{
2321 using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
2322 return exp.has_value() ? result(*std::forward<Exp>(exp))
2323 : result(unexpect, detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error()));
2324}
2325template <class Exp, class F, detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
2326 class Ret = decltype(detail::invoke(std::declval<F>(), std::declval<Exp>().error())),
2327 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2328auto map_error_impl(Exp &&exp, F &&f)
2329{
2330 using result = expected<exp_t<Exp>, monostate>;
2331 if (exp.has_value()) {
2332 return result(*std::forward<Exp>(exp));
2333 }
2334
2335 detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
2336 return result(unexpect, monostate{});
2337}
2338template <class Exp, class F, detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
2339 class Ret = decltype(detail::invoke(std::declval<F>(), std::declval<Exp>().error())),
2340 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2341constexpr auto map_error_impl(Exp &&exp, F &&f)
2342{
2343 using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
2344 return exp.has_value() ? result()
2345 : result(unexpect, detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error()));
2346}
2347template <class Exp, class F, detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
2348 class Ret = decltype(detail::invoke(std::declval<F>(), std::declval<Exp>().error())),
2349 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2350auto map_error_impl(Exp &&exp, F &&f)
2351{
2352 using result = expected<exp_t<Exp>, monostate>;
2353 if (exp.has_value()) {
2354 return result();
2355 }
2356
2357 detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
2358 return result(unexpect, monostate{});
2359}
2360#else
2361template <class Exp, class F, detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
2362 class Ret = decltype(detail::invoke(std::declval<F>(), std::declval<Exp>().error())),
2363 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2364constexpr auto map_error_impl(Exp &&exp, F &&f) -> expected<exp_t<Exp>, detail::decay_t<Ret>>
2365{
2366 using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
2367
2368 return exp.has_value() ? result(*std::forward<Exp>(exp))
2369 : result(unexpect, detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error()));
2370}
2371
2372template <class Exp, class F, detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
2373 class Ret = decltype(detail::invoke(std::declval<F>(), std::declval<Exp>().error())),
2374 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2375auto map_error_impl(Exp &&exp, F &&f) -> expected<exp_t<Exp>, monostate>
2376{
2377 using result = expected<exp_t<Exp>, monostate>;
2378 if (exp.has_value()) {
2379 return result(*std::forward<Exp>(exp));
2380 }
2381
2382 detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
2383 return result(unexpect, monostate{});
2384}
2385
2386template <class Exp, class F, detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
2387 class Ret = decltype(detail::invoke(std::declval<F>(), std::declval<Exp>().error())),
2388 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2389constexpr auto map_error_impl(Exp &&exp, F &&f) -> expected<exp_t<Exp>, detail::decay_t<Ret>>
2390{
2391 using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
2392
2393 return exp.has_value() ? result()
2394 : result(unexpect, detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error()));
2395}
2396
2397template <class Exp, class F, detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
2398 class Ret = decltype(detail::invoke(std::declval<F>(), std::declval<Exp>().error())),
2399 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2400auto map_error_impl(Exp &&exp, F &&f) -> expected<exp_t<Exp>, monostate>
2401{
2402 using result = expected<exp_t<Exp>, monostate>;
2403 if (exp.has_value()) {
2404 return result();
2405 }
2406
2407 detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
2408 return result(unexpect, monostate{});
2409}
2410#endif
2411
2412#ifdef TL_EXPECTED_CXX14
2413template <class Exp, class F, class Ret = decltype(detail::invoke(std::declval<F>(), std::declval<Exp>().error())),
2414 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2415constexpr auto or_else_impl(Exp &&exp, F &&f)
2416{
2417 static_assert(detail::is_expected<Ret>::value, "F must return an expected");
2418 return exp.has_value() ? std::forward<Exp>(exp)
2419 : detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
2420}
2421
2422template <class Exp, class F, class Ret = decltype(detail::invoke(std::declval<F>(), std::declval<Exp>().error())),
2423 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2424detail::decay_t<Exp> or_else_impl(Exp &&exp, F &&f)
2425{
2426 return exp.has_value()
2427 ? std::forward<Exp>(exp)
2428 : (detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error()), std::forward<Exp>(exp));
2429}
2430#else
2431template <class Exp, class F, class Ret = decltype(detail::invoke(std::declval<F>(), std::declval<Exp>().error())),
2432 detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2433auto or_else_impl(Exp &&exp, F &&f) -> Ret
2434{
2435 static_assert(detail::is_expected<Ret>::value, "F must return an expected");
2436 return exp.has_value() ? std::forward<Exp>(exp)
2437 : detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
2438}
2439
2440template <class Exp, class F, class Ret = decltype(detail::invoke(std::declval<F>(), std::declval<Exp>().error())),
2441 detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2442detail::decay_t<Exp> or_else_impl(Exp &&exp, F &&f)
2443{
2444 return exp.has_value()
2445 ? std::forward<Exp>(exp)
2446 : (detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error()), std::forward<Exp>(exp));
2447}
2448#endif
2449} // namespace detail
2450
2451template <class T, class E, class U, class F>
2452constexpr bool operator==(const expected<T, E> &lhs, const expected<U, F> &rhs)
2453{
2454 return (lhs.has_value() != rhs.has_value()) ? false
2455 : (!lhs.has_value() ? lhs.error() == rhs.error() : *lhs == *rhs);
2456}
2457template <class T, class E, class U, class F>
2458constexpr bool operator!=(const expected<T, E> &lhs, const expected<U, F> &rhs)
2459{
2460 return (lhs.has_value() != rhs.has_value()) ? true : (!lhs.has_value() ? lhs.error() != rhs.error() : *lhs != *rhs);
2461}
2462template <class E, class F>
2463constexpr bool operator==(const expected<void, E> &lhs, const expected<void, F> &rhs)
2464{
2465 return (lhs.has_value() != rhs.has_value()) ? false : (!lhs.has_value() ? lhs.error() == rhs.error() : true);
2466}
2467template <class E, class F>
2468constexpr bool operator!=(const expected<void, E> &lhs, const expected<void, F> &rhs)
2469{
2470 return (lhs.has_value() != rhs.has_value()) ? true : (!lhs.has_value() ? lhs.error() == rhs.error() : false);
2471}
2472
2473template <class T, class E, class U>
2474constexpr bool operator==(const expected<T, E> &x, const U &v)
2475{
2476 return x.has_value() ? *x == v : false;
2477}
2478template <class T, class E, class U>
2479constexpr bool operator==(const U &v, const expected<T, E> &x)
2480{
2481 return x.has_value() ? *x == v : false;
2482}
2483template <class T, class E, class U>
2484constexpr bool operator!=(const expected<T, E> &x, const U &v)
2485{
2486 return x.has_value() ? *x != v : true;
2487}
2488template <class T, class E, class U>
2489constexpr bool operator!=(const U &v, const expected<T, E> &x)
2490{
2491 return x.has_value() ? *x != v : true;
2492}
2493
2494template <class T, class E>
2495constexpr bool operator==(const expected<T, E> &x, const unexpected<E> &e)
2496{
2497 return x.has_value() ? false : x.error() == e.value();
2498}
2499template <class T, class E>
2500constexpr bool operator==(const unexpected<E> &e, const expected<T, E> &x)
2501{
2502 return x.has_value() ? false : x.error() == e.value();
2503}
2504template <class T, class E>
2505constexpr bool operator!=(const expected<T, E> &x, const unexpected<E> &e)
2506{
2507 return x.has_value() ? true : x.error() != e.value();
2508}
2509template <class T, class E>
2510constexpr bool operator!=(const unexpected<E> &e, const expected<T, E> &x)
2511{
2512 return x.has_value() ? true : x.error() != e.value();
2513}
2514
2515template <class T, class E,
2516 detail::enable_if_t<(std::is_void<T>::value || std::is_move_constructible<T>::value) &&
2517 detail::is_swappable<T>::value && std::is_move_constructible<E>::value &&
2518 detail::is_swappable<E>::value> * = nullptr>
2519void swap(expected<T, E> &lhs, expected<T, E> &rhs) noexcept(noexcept(lhs.swap(rhs)))
2520{
2521 lhs.swap(rhs);
2522}
2523} // namespace stl
2524} // namespace m5
2525
2526#endif
Definition expected.hpp:1264
Definition expected.hpp:1307
Definition expected.hpp:138
Top level namespace of M5.
Definition base64.cpp:39
STL compatibility functions and classes.
Definition expected.hpp:2191
Definition optional.hpp:132
Definition expected.hpp:1228
Definition expected.hpp:1085
Definition expected.hpp:1017
Definition expected.hpp:1148
Definition expected.hpp:1116
Definition expected.hpp:1050
Definition expected.hpp:452
Definition expected.hpp:402
Definition optional.hpp:266
Definition optional.hpp:251
Definition expected.hpp:441
A tag type to tell optional to construct its value in-place.
Definition optional.hpp:105
Definition expected.hpp:225