10#include <system_error>
15#if defined(__has_include)
16# if __has_include(<version>)
21#if defined(__cpp_lib_expected) && __cpp_lib_expected >= 202202L
23# define THREADSCHEDULE_HAS_STD_EXPECTED 1
24#elif (defined(__cplusplus) && __cplusplus >= 202302L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202302L)
26# define THREADSCHEDULE_HAS_STD_EXPECTED 1
28# define THREADSCHEDULE_HAS_STD_EXPECTED 0
31#ifdef __cpp_exceptions
32# define THREADSCHEDULE_EXPECTED_THROW(ex) throw ex
34# define THREADSCHEDULE_EXPECTED_THROW(ex) ::std::terminate()
55 what() const noexcept ->
char const*
override
57 return "bad expected access";
62class bad_expected_access :
public bad_expected_access<void>
65 explicit bad_expected_access(E error) : error_(
std::move(error)) {}
67 error() const& noexcept -> E const&
72 error() &
noexcept -> E&
77 error() const&& noexcept -> E const&&
79 return std::move(error_);
82 error() &&
noexcept -> E&&
84 return std::move(error_);
98 [[nodiscard]]
constexpr auto
99 error() const& noexcept -> E const&
108 [[nodiscard]]
constexpr auto
109 error() const&& noexcept -> E const&&
111 return std::move(error_);
116 return std::move(error_);
123template <
typename T,
typename E = std::error_code>
130struct expected_value_tag
133struct expected_error_tag
138struct expected_value_holder
140 template <
typename... Args>
141 explicit constexpr expected_value_holder(std::in_place_t, Args&&... args) : value(
std::forward<Args>(args)...)
148struct expected_error_holder
150 template <
typename... Args>
151 explicit constexpr expected_error_holder(std::in_place_t, Args&&... args) : error(
std::forward<Args>(args)...)
157template <
typename T,
typename E>
158class expected_storage_common
161 using value_holder = expected_value_holder<T>;
162 using error_holder = expected_error_holder<E>;
164 template <
typename... Args>
165 explicit constexpr expected_storage_common(expected_value_tag, Args&&... args)
166 : data_(
std::in_place_index<0>,
std::in_place,
std::forward<Args>(args)...)
169 template <
typename... Args>
170 explicit constexpr expected_storage_common(expected_error_tag, Args&&... args)
171 : data_(
std::in_place_index<1>,
std::in_place,
std::forward<Args>(args)...)
175 expected_storage_common(expected_storage_common
const&) =
default;
176 expected_storage_common(expected_storage_common&&) =
default;
177 auto operator=(expected_storage_common
const&) -> expected_storage_common& =
default;
178 auto operator=(expected_storage_common&&) -> expected_storage_common& =
default;
179 ~expected_storage_common() =
default;
181 [[nodiscard]]
constexpr auto
182 has_value() const noexcept ->
bool
184 return data_.index() == 0;
187 value() &
noexcept -> T&
189 return std::get<0>(data_).value;
191 [[nodiscard]]
constexpr auto
192 value() const& noexcept -> T const&
194 return std::get<0>(data_).value;
197 value() &&
noexcept -> T&&
199 return std::move(std::get<0>(data_).value);
201 [[nodiscard]]
constexpr auto
202 value() const&& noexcept -> T const&&
204 return std::move(std::get<0>(data_).value);
207 error() &
noexcept -> E&
209 return std::get<1>(data_).error;
211 [[nodiscard]]
constexpr auto
212 error() const& noexcept -> E const&
214 return std::get<1>(data_).error;
217 error() &&
noexcept -> E&&
219 return std::move(std::get<1>(data_).error);
221 [[nodiscard]]
constexpr auto
222 error() const&& noexcept -> E const&&
224 return std::move(std::get<1>(data_).error);
227 template <
typename U>
229 assign_value(U&& source)
232 value() = std::forward<U>(source);
234 replace_with_value(std::forward<U>(source));
237 template <
typename G>
239 assign_error(G&& source)
242 replace_with_error(std::forward<G>(source));
244 error() = std::forward<G>(source);
247 template <
typename... Args>
249 emplace_value(Args&&... args)
noexcept -> T&
251 data_.template emplace<0>(std::in_place, std::forward<Args>(args)...);
256 copy_assign(expected_storage_common
const& other)
258 if (has_value() &&
other.has_value())
259 value() =
other.value();
260 else if (!has_value() && !
other.has_value())
261 error() =
other.error();
262 else if (
other.has_value())
263 replace_with_value(
other.value());
265 replace_with_error(
other.error());
269 move_assign(expected_storage_common&& other)
271 if (has_value() &&
other.has_value())
272 value() = std::move(other).value();
273 else if (!has_value() && !
other.has_value())
274 error() = std::move(other).error();
275 else if (
other.has_value())
276 replace_with_value(std::move(other).value());
278 replace_with_error(std::move(other).error());
282 swap_storage(expected_storage_common& other)
noexcept(std::is_nothrow_move_constructible_v<T>
283 && std::is_nothrow_move_constructible_v<E>
284 && std::is_nothrow_swappable_v<T>
285 && std::is_nothrow_swappable_v<E>)
287 if (has_value() &&
other.has_value())
292 else if (!has_value() && !
other.has_value())
297 else if (has_value())
298 swap_value_error(*
this, other);
300 swap_value_error(other, *
this);
304 template <
typename U>
306 replace_with_value(U&& source)
308 if constexpr (std::is_nothrow_constructible_v<T, U>)
309 data_.template emplace<0>(std::in_place, std::forward<U>(source));
310 else if constexpr (std::is_nothrow_move_constructible_v<T>)
312 T replacement(std::forward<U>(source));
313 data_.template emplace<0>(std::in_place, std::move(replacement));
317 static_assert(std::is_nothrow_move_constructible_v<E>);
318 E backup(std::move(error()));
319#ifdef __cpp_exceptions
322 data_.template emplace<0>(std::in_place, std::forward<U>(source));
326 data_.template emplace<1>(std::in_place, std::move(backup));
331 data_.template emplace<0>(std::in_place, std::forward<U>(source));
336 template <
typename G>
338 replace_with_error(G&& source)
340 if constexpr (std::is_nothrow_constructible_v<E, G>)
341 data_.template emplace<1>(std::in_place, std::forward<G>(source));
342 else if constexpr (std::is_nothrow_move_constructible_v<E>)
344 E replacement(std::forward<G>(source));
345 data_.template emplace<1>(std::in_place, std::move(replacement));
349 static_assert(std::is_nothrow_move_constructible_v<T>);
350 T backup(std::move(value()));
351#ifdef __cpp_exceptions
354 data_.template emplace<1>(std::in_place, std::forward<G>(source));
358 data_.template emplace<0>(std::in_place, std::move(backup));
363 data_.template emplace<1>(std::in_place, std::forward<G>(source));
369 swap_value_error(expected_storage_common& with_value, expected_storage_common& with_error)
371 if constexpr (std::is_nothrow_move_constructible_v<T>)
373 T backup(std::move(with_value.value()));
374#ifdef __cpp_exceptions
377 with_value.data_.template emplace<1>(std::in_place, std::move(with_error.error()));
381 with_value.data_.template emplace<0>(std::in_place, std::move(backup));
385 with_value.data_.template emplace<1>(std::in_place, std::move(with_error.error()));
387 with_error.data_.template emplace<0>(std::in_place, std::move(backup));
391 static_assert(std::is_nothrow_move_constructible_v<E>);
392 E backup(std::move(with_error.error()));
393#ifdef __cpp_exceptions
396 with_error.data_.template emplace<0>(std::in_place, std::move(with_value.value()));
400 with_error.data_.template emplace<1>(std::in_place, std::move(backup));
404 with_error.data_.template emplace<0>(std::in_place, std::move(with_value.value()));
406 with_value.data_.template emplace<1>(std::in_place, std::move(backup));
410 std::variant<value_holder, error_holder> data_;
413template <
typename T,
typename E>
414inline constexpr bool expected_copy_assignable_v
415 = std::is_copy_constructible_v<T> && std::is_copy_constructible_v<E> && std::is_copy_assignable_v<T>
416 && std::is_copy_assignable_v<E>
417 && (std::is_nothrow_move_constructible_v<T> || std::is_nothrow_move_constructible_v<E>);
418template <
typename T,
typename E>
419inline constexpr bool expected_move_assignable_v
420 = std::is_move_constructible_v<T> && std::is_move_constructible_v<E> && std::is_move_assignable_v<T>
421 && std::is_move_assignable_v<E>
422 && (std::is_nothrow_move_constructible_v<T> || std::is_nothrow_move_constructible_v<E>);
424template <
typename T,
typename E,
bool Copy = expected_copy_assignable_v<T, E>,
425 bool Move = expected_move_assignable_v<T, E>>
426class expected_storage;
428template <
typename T,
typename E>
429class expected_storage<T, E, true, true> :
public expected_storage_common<T, E>
431 using base = expected_storage_common<T, E>;
435 expected_storage(expected_storage
const&) =
default;
436 expected_storage(expected_storage&&) =
default;
438 operator=(expected_storage
const& other) -> expected_storage&
441 this->copy_assign(other);
445 operator=(expected_storage&& other)
noexcept(std::is_nothrow_move_constructible_v<T>
446 && std::is_nothrow_move_constructible_v<E>
447 && std::is_nothrow_move_assignable_v<T>
448 && std::is_nothrow_move_assignable_v<E>) -> expected_storage&
451 this->move_assign(std::move(other));
456template <
typename T,
typename E>
457class expected_storage<T, E, true, false> :
public expected_storage_common<T, E>
459 using base = expected_storage_common<T, E>;
463 expected_storage(expected_storage
const&) =
default;
464 expected_storage(expected_storage&&) =
default;
466 operator=(expected_storage
const& other) -> expected_storage&
469 this->copy_assign(other);
472 auto operator=(expected_storage&&) -> expected_storage& =
delete;
475template <
typename T,
typename E>
476class expected_storage<T, E, false, true> :
public expected_storage_common<T, E>
478 using base = expected_storage_common<T, E>;
482 expected_storage(expected_storage
const&) =
default;
483 expected_storage(expected_storage&&) =
default;
484 auto operator=(expected_storage
const&) -> expected_storage& =
delete;
486 operator=(expected_storage&& other)
noexcept(std::is_nothrow_move_constructible_v<T>
487 && std::is_nothrow_move_constructible_v<E>
488 && std::is_nothrow_move_assignable_v<T>
489 && std::is_nothrow_move_assignable_v<E>) -> expected_storage&
492 this->move_assign(std::move(other));
497template <
typename T,
typename E>
498class expected_storage<T, E, false, false> :
public expected_storage_common<T, E>
500 using base = expected_storage_common<T, E>;
504 expected_storage(expected_storage
const&) =
default;
505 expected_storage(expected_storage&&) =
default;
506 auto operator=(expected_storage
const&) -> expected_storage& =
delete;
507 auto operator=(expected_storage&&) -> expected_storage& =
delete;
513template <
typename T,
typename E>
521 template <
typename U = T, std::enable_if_t<std::is_default_constructible_v<U>,
int> = 0>
522 constexpr expected() : storage_(detail::expected_value_tag{})
525 template <
typename U = T, std::enable_if_t<!std::is_default_constructible_v<U>,
int> = 0>
534 template <
typename U = T, std::enable_if_t<!std::is_same_v<std::decay_t<U>, expected>
535 && !std::is_same_v<std::decay_t<U>, std::in_place_t>
536 && !std::is_same_v<std::decay_t<U>, unexpected<E>>
537 && std::is_constructible_v<T, U> && std::is_convertible_v<U, T>,
542 template <
typename U = T, std::enable_if_t<!std::is_same_v<std::decay_t<U>, expected>
543 && !std::is_same_v<std::decay_t<U>, std::in_place_t>
544 && !std::is_same_v<std::decay_t<U>, unexpected<E>>
545 && std::is_constructible_v<T, U> && !std::is_convertible_v<U, T>,
550 template <
typename... Args, std::enable_if_t<std::is_constructible_v<T, Args...>,
int> = 0>
551 constexpr explicit expected(std::in_place_t, Args&&... args)
552 : storage_(detail::expected_value_tag{},
std::forward<Args>(args)...)
557 template <
typename... Args, std::enable_if_t<std::is_constructible_v<E, Args...>,
int> = 0>
559 : storage_(detail::expected_error_tag{},
std::forward<Args>(args)...)
563 template <
typename U = T,
564 std::enable_if_t<!std::is_same_v<std::decay_t<U>,
expected> && std::is_constructible_v<T, U>
565 && std::is_assignable_v<T&, U>
566 && (std::is_nothrow_constructible_v<T, U> || std::is_nothrow_move_constructible_v<T>
567 || std::is_nothrow_move_constructible_v<E>),
572 storage_.assign_value(std::forward<U>(
value));
575 template <
typename G, std::enable_if_t<std::is_constructible_v<E, G const&> && std::is_assignable_v<E&, G const&>
576 && (std::is_nothrow_constructible_v<E, G const&>
577 || std::is_nothrow_move_constructible_v<E>
578 || std::is_nothrow_move_constructible_v<T>),
583 storage_.assign_error(
error.error());
586 template <
typename G,
587 std::enable_if_t<std::is_constructible_v<E, G> && std::is_assignable_v<E&, G>
588 && (std::is_nothrow_constructible_v<E, G> || std::is_nothrow_move_constructible_v<E>
589 || std::is_nothrow_move_constructible_v<T>),
594 storage_.assign_error(std::move(
error).error());
598 [[nodiscard]]
constexpr auto
601 return storage_.has_value();
604 operator bool() const noexcept
611 return &storage_.value();
616 return &storage_.value();
621 return storage_.value();
623 [[nodiscard]]
constexpr auto
626 return storage_.value();
631 return std::move(storage_).value();
633 [[nodiscard]]
constexpr auto
636 return std::move(storage_).value();
644 return storage_.value();
651 return storage_.value();
658 return std::move(storage_).value();
665 return std::move(storage_).value();
670 return storage_.error();
672 [[nodiscard]]
constexpr auto
675 return storage_.error();
680 return std::move(storage_).error();
682 [[nodiscard]]
constexpr auto
683 error() const&& noexcept -> E const&&
685 return std::move(storage_).error();
688 template <
typename U>
692 return has_value() ? storage_.value() :
static_cast<T
>(std::forward<U>(fallback));
694 template <
typename U>
698 return has_value() ? std::move(storage_).value() :
static_cast<T
>(std::forward<U>(fallback));
700 template <
typename... Args, std::enable_if_t<std::is_nothrow_constructible_v<T, Args...>,
int> = 0>
704 return storage_.emplace_value(std::forward<Args>(args)...);
707 swap(
expected& other)
noexcept(std::is_nothrow_move_constructible_v<T> && std::is_nothrow_move_constructible_v<E>
708 && std::is_nothrow_swappable_v<T> && std::is_nothrow_swappable_v<E>)
710 storage_.swap_storage(other.storage_);
713 template <
typename F>
717 return and_then_impl(*
this, std::forward<F>(f));
719 template <
typename F>
723 return and_then_impl(*
this, std::forward<F>(f));
725 template <
typename F>
729 return and_then_impl(std::move(*
this), std::forward<F>(f));
731 template <
typename F>
735 return and_then_impl(std::move(*
this), std::forward<F>(f));
737 template <
typename F>
741 return or_else_impl(*
this, std::forward<F>(f));
743 template <
typename F>
747 return or_else_impl(*
this, std::forward<F>(f));
749 template <
typename F>
753 return or_else_impl(std::move(*
this), std::forward<F>(f));
755 template <
typename F>
759 return or_else_impl(std::move(*
this), std::forward<F>(f));
761 template <
typename F>
765 return transform_impl(*
this, std::forward<F>(f));
767 template <
typename F>
771 return transform_impl(*
this, std::forward<F>(f));
773 template <
typename F>
777 return transform_impl(std::move(*
this), std::forward<F>(f));
779 template <
typename F>
783 return transform_impl(std::move(*
this), std::forward<F>(f));
785 template <
typename F>
789 return transform_error_impl(*
this, std::forward<F>(f));
791 template <
typename F>
795 return transform_error_impl(*
this, std::forward<F>(f));
797 template <
typename F>
801 return transform_error_impl(std::move(*
this), std::forward<F>(f));
803 template <
typename F>
807 return transform_error_impl(std::move(*
this), std::forward<F>(f));
810#if THREADSCHEDULE_HAS_STD_EXPECTED
811 template <
typename U = T,
typename G = E,
812 std::enable_if_t<std::is_copy_constructible_v<U> && std::is_copy_constructible_v<G>,
int> = 0>
813 operator std::expected<T, E>() const&
816 return std::expected<T, E>(std::in_place, storage_.value());
817 return std::expected<T, E>(std::unexpect, storage_.error());
819 template <
typename U = T,
typename G = E,
820 std::enable_if_t<std::is_move_constructible_v<U> && std::is_move_constructible_v<G>,
int> = 0>
821 operator std::expected<T, E>() &&
824 return std::expected<T, E>(std::in_place, std::move(storage_).
value());
825 return std::expected<T, E>(std::unexpect, std::move(storage_).
error());
829 template <
typename T2,
typename E2>
833 if (lhs.has_value() != rhs.has_value())
835 return lhs.has_value() ? *lhs == *rhs : lhs.error() == rhs.error();
837 template <
typename T2,
typename E2>
841 return !(lhs == rhs);
843 template <
typename T2, std::enable_if_t<!std::is_same_v<expected, std::decay_t<T2>>,
int> = 0>
847 return lhs.has_value() && *lhs == rhs;
849 template <
typename T2, std::enable_if_t<!std::is_same_v<expected, std::decay_t<T2>>,
int> = 0>
853 return rhs.has_value() && lhs == *rhs;
855 template <
typename T2, std::enable_if_t<!std::is_same_v<expected, std::decay_t<T2>>,
int> = 0>
859 return !(lhs == rhs);
861 template <
typename T2, std::enable_if_t<!std::is_same_v<expected, std::decay_t<T2>>,
int> = 0>
865 return !(lhs == rhs);
867 template <
typename E2>
871 return !lhs.has_value() && lhs.error() == rhs.error();
873 template <
typename E2>
879 template <
typename E2>
883 return !(lhs == rhs);
885 template <
typename E2>
889 return !(rhs == lhs);
893 template <
typename Self,
typename F>
895 and_then_impl(Self&& self, F&& f)
897 using result_type = std::invoke_result_t<F, decltype(*std::forward<Self>(self))>;
898 if (self.has_value())
899 return std::invoke(std::forward<F>(f), *std::forward<Self>(self));
900 return result_type(
unexpect, std::forward<Self>(self).
error());
902 template <
typename Self,
typename F>
904 or_else_impl(Self&& self, F&& f)
906 using result_type = std::invoke_result_t<F, decltype(std::forward<Self>(self).error())>;
907 if (self.has_value())
908 return result_type(*std::forward<Self>(self));
909 return std::invoke(std::forward<F>(f), std::forward<Self>(self).
error());
911 template <
typename Self,
typename F>
913 transform_impl(Self&& self, F&& f)
915 using result_value = std::remove_cv_t<std::invoke_result_t<F, decltype(*std::forward<Self>(self))>>;
916 if (self.has_value())
918 if constexpr (std::is_void_v<result_value>)
920 std::invoke(std::forward<F>(f), *std::forward<Self>(self));
921 return expected<void, E>();
924 return expected<result_value, E>(std::in_place, std::invoke(std::forward<F>(f), *std::forward<Self>(self)));
926 return expected<result_value, E>(
unexpect, std::forward<Self>(self).
error());
928 template <
typename Self,
typename F>
930 transform_error_impl(Self&& self, F&& f)
932 using result_error = std::remove_cv_t<std::invoke_result_t<F, decltype(std::forward<Self>(self).error())>>;
933 if (self.has_value())
934 return expected<T, result_error>(*std::forward<Self>(self));
935 return expected<T, result_error>(
unexpect, std::invoke(std::forward<F>(f), std::forward<Self>(self).
error()));
938 detail::expected_storage<T, E> storage_;
944 using storage_type = detail::expected_storage<std::monostate, E>;
951 constexpr expected() : storage_(detail::expected_value_tag{}) {}
958 template <
typename... Args, std::enable_if_t<std::is_constructible_v<E, Args...>,
int> = 0>
960 : storage_(detail::expected_error_tag{},
std::forward<Args>(args)...)
966 template <
typename G, std::enable_if_t<std::is_constructible_v<E, G const&> && std::is_assignable_v<E&, G const&>
967 && (std::is_nothrow_constructible_v<E, G const&>
968 || std::is_nothrow_move_constructible_v<E>),
973 storage_.assign_error(
error.error());
976 template <
typename G,
977 std::enable_if_t<std::is_constructible_v<E, G> && std::is_assignable_v<E&, G>
978 && (std::is_nothrow_constructible_v<E, G> || std::is_nothrow_move_constructible_v<E>),
983 storage_.assign_error(std::move(
error).error());
987 [[nodiscard]]
constexpr auto
990 return storage_.has_value();
993 operator bool() const noexcept
1006 return storage_.error();
1008 [[nodiscard]]
constexpr auto
1011 return storage_.error();
1016 return std::move(storage_).
error();
1018 [[nodiscard]]
constexpr auto
1021 return std::move(storage_).error();
1026 storage_.emplace_value();
1029 swap(
expected& other)
noexcept(std::is_nothrow_move_constructible_v<E> && std::is_nothrow_swappable_v<E>)
1031 storage_.swap_storage(other.storage_);
1034 template <
typename F>
1038 return and_then_impl(*
this, std::forward<F>(f));
1040 template <
typename F>
1044 return and_then_impl(*
this, std::forward<F>(f));
1046 template <
typename F>
1050 return and_then_impl(std::move(*
this), std::forward<F>(f));
1052 template <
typename F>
1056 return and_then_impl(std::move(*
this), std::forward<F>(f));
1058 template <
typename F>
1062 return or_else_impl(*
this, std::forward<F>(f));
1064 template <
typename F>
1068 return or_else_impl(*
this, std::forward<F>(f));
1070 template <
typename F>
1074 return or_else_impl(std::move(*
this), std::forward<F>(f));
1076 template <
typename F>
1080 return or_else_impl(std::move(*
this), std::forward<F>(f));
1082 template <
typename F>
1086 return transform_impl(*
this, std::forward<F>(f));
1088 template <
typename F>
1092 return transform_impl(*
this, std::forward<F>(f));
1094 template <
typename F>
1098 return transform_impl(std::move(*
this), std::forward<F>(f));
1100 template <
typename F>
1104 return transform_impl(std::move(*
this), std::forward<F>(f));
1106 template <
typename F>
1110 return transform_error_impl(*
this, std::forward<F>(f));
1112 template <
typename F>
1116 return transform_error_impl(*
this, std::forward<F>(f));
1118 template <
typename F>
1122 return transform_error_impl(std::move(*
this), std::forward<F>(f));
1124 template <
typename F>
1128 return transform_error_impl(std::move(*
this), std::forward<F>(f));
1131#if THREADSCHEDULE_HAS_STD_EXPECTED
1132 template <
typename G = E, std::enable_if_t<std::is_copy_constructible_v<G>,
int> = 0>
1133 operator std::expected<void, E>() const&
1136 return std::expected<void, E>();
1137 return std::expected<void, E>(std::unexpect, storage_.error());
1139 template <
typename G = E, std::enable_if_t<std::is_move_constructible_v<G>,
int> = 0>
1140 operator std::expected<void, E>() &&
1143 return std::expected<void, E>();
1144 return std::expected<void, E>(std::unexpect, std::move(storage_).
error());
1148 template <
typename E2>
1152 if (lhs.has_value() != rhs.has_value())
1154 return lhs.has_value() || lhs.error() == rhs.error();
1156 template <
typename E2>
1160 return !(lhs == rhs);
1162 template <
typename E2>
1166 return !lhs.has_value() && lhs.error() == rhs.error();
1168 template <
typename E2>
1174 template <
typename E2>
1178 return !(lhs == rhs);
1180 template <
typename E2>
1184 return !(rhs == lhs);
1188 template <
typename Self,
typename F>
1190 and_then_impl(Self&& self, F&& f)
1192 using result_type = std::invoke_result_t<F>;
1193 if (self.has_value())
1194 return std::invoke(std::forward<F>(f));
1195 return result_type(
unexpect, std::forward<Self>(self).
error());
1197 template <
typename Self,
typename F>
1199 or_else_impl(Self&& self, F&& f)
1201 using result_type = std::invoke_result_t<F, decltype(std::forward<Self>(self).error())>;
1202 if (self.has_value())
1203 return result_type();
1204 return std::invoke(std::forward<F>(f), std::forward<Self>(self).
error());
1206 template <
typename Self,
typename F>
1208 transform_impl(Self&& self, F&& f)
1210 using result_value = std::remove_cv_t<std::invoke_result_t<F>>;
1211 if (self.has_value())
1213 if constexpr (std::is_void_v<result_value>)
1215 std::invoke(std::forward<F>(f));
1216 return expected<void, E>();
1219 return expected<result_value, E>(std::in_place, std::invoke(std::forward<F>(f)));
1221 return expected<result_value, E>(
unexpect, std::forward<Self>(self).
error());
1223 template <
typename Self,
typename F>
1225 transform_error_impl(Self&& self, F&& f)
1227 using result_error = std::remove_cv_t<std::invoke_result_t<F, decltype(std::forward<Self>(self).error())>>;
1228 if (self.has_value())
1229 return expected<void, result_error>();
1230 return expected<void, result_error>(
unexpect, std::invoke(std::forward<F>(f), std::forward<Self>(self).
error()));
1233 storage_type storage_;
1236template <
typename T,
typename E>
1245#undef THREADSCHEDULE_EXPECTED_THROW
auto transform(F &&f) const &
constexpr expected(unexpect_t, Args &&... args)
auto transform_error(F &&f) &
auto and_then(F &&f) const &&
auto and_then(F &&f) const &
void swap(expected &other) noexcept(std::is_nothrow_move_constructible_v< E > &&std::is_nothrow_swappable_v< E >)
friend auto operator==(unexpected< E2 > const &lhs, expected const &rhs) -> bool
auto operator=(expected &&) -> expected &=default
auto or_else(F &&f) const &&
constexpr expected(unexpected< E > const &error)
auto operator=(expected const &) -> expected &=default
constexpr auto has_value() const noexcept -> bool
expected(expected &&)=default
friend auto operator!=(unexpected< E2 > const &lhs, expected const &rhs) -> bool
constexpr auto error() &&noexcept -> E &&
auto transform_error(F &&f) const &&
constexpr auto error() const &&noexcept -> E const &&
friend auto operator!=(expected const &lhs, expected< void, E2 > const &rhs) -> bool
auto operator=(unexpected< G > const &error) -> expected &
constexpr auto error() const &noexcept -> E const &
expected(expected const &)=default
auto transform_error(F &&f) &&
friend auto operator==(expected const &lhs, unexpected< E2 > const &rhs) -> bool
auto transform(F &&f) const &&
auto or_else(F &&f) const &
constexpr expected(unexpected< E > &&error)
auto transform_error(F &&f) const &
friend auto operator==(expected const &lhs, expected< void, E2 > const &rhs) -> bool
friend auto operator!=(expected const &lhs, unexpected< E2 > const &rhs) -> bool
constexpr auto error() &noexcept -> E &
constexpr expected(unexpected< E > &&error)
auto and_then(F &&f) const &&
constexpr expected(unexpected< E > const &error)
friend auto operator!=(expected const &lhs, T2 const &rhs) -> bool
auto emplace(Args &&... args) noexcept -> T &
constexpr auto error() const &noexcept -> E const &
constexpr auto operator*() const &&noexcept -> T const &&
auto value() const &&-> T const &&
friend auto operator==(T2 const &lhs, expected const &rhs) -> bool
constexpr expected(unexpect_t, Args &&... args)
friend auto operator!=(expected const &lhs, expected< T2, E2 > const &rhs) -> bool
constexpr auto operator*() &noexcept -> T &
void swap(expected &other) noexcept(std::is_nothrow_move_constructible_v< T > &&std::is_nothrow_move_constructible_v< E > &&std::is_nothrow_swappable_v< T > &&std::is_nothrow_swappable_v< E >)
friend auto operator==(unexpected< E2 > const &lhs, expected const &rhs) -> bool
auto transform(F &&f) const &&
auto or_else(F &&f) const &&
constexpr auto operator->() const noexcept -> T const *
friend auto operator!=(T2 const &lhs, expected const &rhs) -> bool
auto value() const &-> T const &
auto operator=(expected const &) -> expected &=default
friend auto operator!=(unexpected< E2 > const &lhs, expected const &rhs) -> bool
constexpr auto operator->() noexcept -> T *
auto operator=(expected &&) -> expected &=default
auto and_then(F &&f) const &
friend auto operator==(expected const &lhs, expected< T2, E2 > const &rhs) -> bool
friend auto operator==(expected const &lhs, T2 const &rhs) -> bool
expected(expected const &)=default
auto transform_error(F &&f) &&
expected(expected &&)=default
auto transform_error(F &&f) const &&
constexpr auto has_value() const noexcept -> bool
auto value_or(U &&fallback) const &-> T
auto transform(F &&f) const &
constexpr auto error() const &&noexcept -> E const &&
friend auto operator==(expected const &lhs, unexpected< E2 > const &rhs) -> bool
constexpr auto error() &&noexcept -> E &&
constexpr expected(std::in_place_t, Args &&... args)
constexpr expected(U &&value)
auto transform_error(F &&f) &
constexpr auto operator*() &&noexcept -> T &&
auto or_else(F &&f) const &
constexpr auto error() &noexcept -> E &
auto operator=(unexpected< G > const &error) -> expected &
auto transform_error(F &&f) const &
friend auto operator!=(expected const &lhs, unexpected< E2 > const &rhs) -> bool
constexpr auto operator*() const &noexcept -> T const &
auto value_or(U &&fallback) &&-> T
constexpr auto error() &&noexcept -> E &&
constexpr auto error() const &&noexcept -> E const &&
constexpr unexpected(E &&error)
constexpr auto error() const &noexcept -> E const &
constexpr auto error() &noexcept -> E &
constexpr unexpected(E const &error)
#define THREADSCHEDULE_EXPECTED_THROW(ex)
@ other
Standard round-robin time-sharing.
constexpr unexpect_t unexpect
void swap(expected< T, E > &lhs, expected< T, E > &rhs) noexcept(noexcept(lhs.swap(rhs)))