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