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