| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444 |
- ///
- // expected - An implementation of std::expected with extensions
- // Written in 2017 by Sy Brand (tartanllama@gmail.com, @TartanLlama)
- //
- // Documentation available at http://tl.tartanllama.xyz/
- //
- // To the extent possible under law, the author(s) have dedicated all
- // copyright and related and neighboring rights to this software to the
- // public domain worldwide. This software is distributed without any warranty.
- //
- // You should have received a copy of the CC0 Public Domain Dedication
- // along with this software. If not, see
- // <http://creativecommons.org/publicdomain/zero/1.0/>.
- ///
- #ifndef TL_EXPECTED_HPP
- #define TL_EXPECTED_HPP
- #define TL_EXPECTED_VERSION_MAJOR 1
- #define TL_EXPECTED_VERSION_MINOR 1
- #define TL_EXPECTED_VERSION_PATCH 0
- #include <exception>
- #include <functional>
- #include <type_traits>
- #include <utility>
- #if defined(__EXCEPTIONS) || defined(_CPPUNWIND)
- #define TL_EXPECTED_EXCEPTIONS_ENABLED
- #endif
- #if (defined(_MSC_VER) && _MSC_VER == 1900)
- #define TL_EXPECTED_MSVC2015
- #define TL_EXPECTED_MSVC2015_CONSTEXPR
- #else
- #define TL_EXPECTED_MSVC2015_CONSTEXPR constexpr
- #endif
- #if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \
- !defined(__clang__))
- #define TL_EXPECTED_GCC49
- #endif
- #if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && \
- !defined(__clang__))
- #define TL_EXPECTED_GCC54
- #endif
- #if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 5 && \
- !defined(__clang__))
- #define TL_EXPECTED_GCC55
- #endif
- #if !defined(TL_ASSERT)
- //can't have assert in constexpr in C++11 and GCC 4.9 has a compiler bug
- #if (__cplusplus > 201103L) && !defined(TL_EXPECTED_GCC49)
- #include <cassert>
- #define TL_ASSERT(x) assert(x)
- #else
- #define TL_ASSERT(x)
- #endif
- #endif
- #if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \
- !defined(__clang__))
- // GCC < 5 doesn't support overloading on const&& for member functions
- #define TL_EXPECTED_NO_CONSTRR
- // GCC < 5 doesn't support some standard C++11 type traits
- #define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
- std::has_trivial_copy_constructor<T>
- #define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
- std::has_trivial_copy_assign<T>
- // This one will be different for GCC 5.7 if it's ever supported
- #define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
- std::is_trivially_destructible<T>
- // GCC 5 < v < 8 has a bug in is_trivially_copy_constructible which breaks
- // std::vector for non-copyable types
- #elif (defined(__GNUC__) && __GNUC__ < 8 && !defined(__clang__))
- #ifndef TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
- #define TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
- namespace tl {
- namespace detail {
- template <class T>
- struct is_trivially_copy_constructible
- : std::is_trivially_copy_constructible<T> {};
- #ifdef _GLIBCXX_VECTOR
- template <class T, class A>
- struct is_trivially_copy_constructible<std::vector<T, A>> : std::false_type {};
- #endif
- } // namespace detail
- } // namespace tl
- #endif
- #define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
- tl::detail::is_trivially_copy_constructible<T>
- #define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
- std::is_trivially_copy_assignable<T>
- #define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
- std::is_trivially_destructible<T>
- #else
- #define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
- std::is_trivially_copy_constructible<T>
- #define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
- std::is_trivially_copy_assignable<T>
- #define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
- std::is_trivially_destructible<T>
- #endif
- #if __cplusplus > 201103L
- #define TL_EXPECTED_CXX14
- #endif
- #ifdef TL_EXPECTED_GCC49
- #define TL_EXPECTED_GCC49_CONSTEXPR
- #else
- #define TL_EXPECTED_GCC49_CONSTEXPR constexpr
- #endif
- #if (__cplusplus == 201103L || defined(TL_EXPECTED_MSVC2015) || \
- defined(TL_EXPECTED_GCC49))
- #define TL_EXPECTED_11_CONSTEXPR
- #else
- #define TL_EXPECTED_11_CONSTEXPR constexpr
- #endif
- namespace tl {
- template <class T, class E> class expected;
- #ifndef TL_MONOSTATE_INPLACE_MUTEX
- #define TL_MONOSTATE_INPLACE_MUTEX
- class monostate {};
- struct in_place_t {
- explicit in_place_t() = default;
- };
- static constexpr in_place_t in_place{};
- #endif
- template <class E> class unexpected {
- public:
- static_assert(!std::is_same<E, void>::value, "E must not be void");
- unexpected() = delete;
- constexpr explicit unexpected(const E &e) : m_val(e) {}
- constexpr explicit unexpected(E &&e) : m_val(std::move(e)) {}
- template <class... Args, typename std::enable_if<std::is_constructible<
- E, Args &&...>::value>::type * = nullptr>
- constexpr explicit unexpected(Args &&...args)
- : m_val(std::forward<Args>(args)...) {}
- template <
- class U, class... Args,
- typename std::enable_if<std::is_constructible<
- E, std::initializer_list<U> &, Args &&...>::value>::type * = nullptr>
- constexpr explicit unexpected(std::initializer_list<U> l, Args &&...args)
- : m_val(l, std::forward<Args>(args)...) {}
- constexpr const E &value() const & { return m_val; }
- TL_EXPECTED_11_CONSTEXPR E &value() & { return m_val; }
- TL_EXPECTED_11_CONSTEXPR E &&value() && { return std::move(m_val); }
- constexpr const E &&value() const && { return std::move(m_val); }
- private:
- E m_val;
- };
- #ifdef __cpp_deduction_guides
- template <class E> unexpected(E) -> unexpected<E>;
- #endif
- template <class E>
- constexpr bool operator==(const unexpected<E> &lhs, const unexpected<E> &rhs) {
- return lhs.value() == rhs.value();
- }
- template <class E>
- constexpr bool operator!=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
- return lhs.value() != rhs.value();
- }
- template <class E>
- constexpr bool operator<(const unexpected<E> &lhs, const unexpected<E> &rhs) {
- return lhs.value() < rhs.value();
- }
- template <class E>
- constexpr bool operator<=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
- return lhs.value() <= rhs.value();
- }
- template <class E>
- constexpr bool operator>(const unexpected<E> &lhs, const unexpected<E> &rhs) {
- return lhs.value() > rhs.value();
- }
- template <class E>
- constexpr bool operator>=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
- return lhs.value() >= rhs.value();
- }
- template <class E>
- unexpected<typename std::decay<E>::type> make_unexpected(E &&e) {
- return unexpected<typename std::decay<E>::type>(std::forward<E>(e));
- }
- struct unexpect_t {
- unexpect_t() = default;
- };
- static constexpr unexpect_t unexpect{};
- namespace detail {
- template <typename E>
- [[noreturn]] TL_EXPECTED_11_CONSTEXPR void throw_exception(E &&e) {
- #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
- throw std::forward<E>(e);
- #else
- (void)e;
- #ifdef _MSC_VER
- __assume(0);
- #else
- __builtin_unreachable();
- #endif
- #endif
- }
- #ifndef TL_TRAITS_MUTEX
- #define TL_TRAITS_MUTEX
- // C++14-style aliases for brevity
- template <class T> using remove_const_t = typename std::remove_const<T>::type;
- template <class T>
- using remove_reference_t = typename std::remove_reference<T>::type;
- template <class T> using decay_t = typename std::decay<T>::type;
- template <bool E, class T = void>
- using enable_if_t = typename std::enable_if<E, T>::type;
- template <bool B, class T, class F>
- using conditional_t = typename std::conditional<B, T, F>::type;
- // std::conjunction from C++17
- template <class...> struct conjunction : std::true_type {};
- template <class B> struct conjunction<B> : B {};
- template <class B, class... Bs>
- struct conjunction<B, Bs...>
- : std::conditional<bool(B::value), conjunction<Bs...>, B>::type {};
- #if defined(_LIBCPP_VERSION) && __cplusplus == 201103L
- #define TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
- #endif
- // In C++11 mode, there's an issue in libc++'s std::mem_fn
- // which results in a hard-error when using it in a noexcept expression
- // in some cases. This is a check to workaround the common failing case.
- #ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
- template <class T>
- struct is_pointer_to_non_const_member_func : std::false_type {};
- template <class T, class Ret, class... Args>
- struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...)>
- : std::true_type {};
- template <class T, class Ret, class... Args>
- struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) &>
- : std::true_type {};
- template <class T, class Ret, class... Args>
- struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) &&>
- : std::true_type {};
- template <class T, class Ret, class... Args>
- struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile>
- : std::true_type {};
- template <class T, class Ret, class... Args>
- struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile &>
- : std::true_type {};
- template <class T, class Ret, class... Args>
- struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile &&>
- : std::true_type {};
- template <class T> struct is_const_or_const_ref : std::false_type {};
- template <class T> struct is_const_or_const_ref<T const &> : std::true_type {};
- template <class T> struct is_const_or_const_ref<T const> : std::true_type {};
- #endif
- // std::invoke from C++17
- // https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround
- template <
- typename Fn, typename... Args,
- #ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
- typename = enable_if_t<!(is_pointer_to_non_const_member_func<Fn>::value &&
- is_const_or_const_ref<Args...>::value)>,
- #endif
- typename = enable_if_t<std::is_member_pointer<decay_t<Fn>>::value>, int = 0>
- constexpr auto invoke(Fn &&f, Args &&...args) noexcept(
- noexcept(std::mem_fn(f)(std::forward<Args>(args)...)))
- -> decltype(std::mem_fn(f)(std::forward<Args>(args)...)) {
- return std::mem_fn(f)(std::forward<Args>(args)...);
- }
- template <typename Fn, typename... Args,
- typename = enable_if_t<!std::is_member_pointer<decay_t<Fn>>::value>>
- constexpr auto invoke(Fn &&f, Args &&...args) noexcept(
- noexcept(std::forward<Fn>(f)(std::forward<Args>(args)...)))
- -> decltype(std::forward<Fn>(f)(std::forward<Args>(args)...)) {
- return std::forward<Fn>(f)(std::forward<Args>(args)...);
- }
- // std::invoke_result from C++17
- template <class F, class, class... Us> struct invoke_result_impl;
- template <class F, class... Us>
- struct invoke_result_impl<
- F,
- decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...), void()),
- Us...> {
- using type =
- decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...));
- };
- template <class F, class... Us>
- using invoke_result = invoke_result_impl<F, void, Us...>;
- template <class F, class... Us>
- using invoke_result_t = typename invoke_result<F, Us...>::type;
- #if defined(_MSC_VER) && _MSC_VER <= 1900
- // TODO make a version which works with MSVC 2015
- template <class T, class U = T> struct is_swappable : std::true_type {};
- template <class T, class U = T> struct is_nothrow_swappable : std::true_type {};
- #else
- // https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept
- namespace swap_adl_tests {
- // if swap ADL finds this then it would call std::swap otherwise (same
- // signature)
- struct tag {};
- template <class T> tag swap(T &, T &);
- template <class T, std::size_t N> tag swap(T (&a)[N], T (&b)[N]);
- // helper functions to test if an unqualified swap is possible, and if it
- // becomes std::swap
- template <class, class> std::false_type can_swap(...) noexcept(false);
- template <class T, class U,
- class = decltype(swap(std::declval<T &>(), std::declval<U &>()))>
- std::true_type can_swap(int) noexcept(noexcept(swap(std::declval<T &>(),
- std::declval<U &>())));
- template <class, class> std::false_type uses_std(...);
- template <class T, class U>
- std::is_same<decltype(swap(std::declval<T &>(), std::declval<U &>())), tag>
- uses_std(int);
- template <class T>
- struct is_std_swap_noexcept
- : std::integral_constant<bool,
- std::is_nothrow_move_constructible<T>::value &&
- std::is_nothrow_move_assignable<T>::value> {};
- template <class T, std::size_t N>
- struct is_std_swap_noexcept<T[N]> : is_std_swap_noexcept<T> {};
- template <class T, class U>
- struct is_adl_swap_noexcept
- : std::integral_constant<bool, noexcept(can_swap<T, U>(0))> {};
- } // namespace swap_adl_tests
- template <class T, class U = T>
- struct is_swappable
- : std::integral_constant<
- bool,
- decltype(detail::swap_adl_tests::can_swap<T, U>(0))::value &&
- (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value ||
- (std::is_move_assignable<T>::value &&
- std::is_move_constructible<T>::value))> {};
- template <class T, std::size_t N>
- struct is_swappable<T[N], T[N]>
- : std::integral_constant<
- bool,
- decltype(detail::swap_adl_tests::can_swap<T[N], T[N]>(0))::value &&
- (!decltype(detail::swap_adl_tests::uses_std<T[N], T[N]>(
- 0))::value ||
- is_swappable<T, T>::value)> {};
- template <class T, class U = T>
- struct is_nothrow_swappable
- : std::integral_constant<
- bool,
- is_swappable<T, U>::value &&
- ((decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value &&
- detail::swap_adl_tests::is_std_swap_noexcept<T>::value) ||
- (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value &&
- detail::swap_adl_tests::is_adl_swap_noexcept<T, U>::value))> {};
- #endif
- #endif
- // Trait for checking if a type is a tl::expected
- template <class T> struct is_expected_impl : std::false_type {};
- template <class T, class E>
- struct is_expected_impl<expected<T, E>> : std::true_type {};
- template <class T> using is_expected = is_expected_impl<decay_t<T>>;
- template <class T, class E, class U>
- using expected_enable_forward_value = detail::enable_if_t<
- std::is_constructible<T, U &&>::value &&
- !std::is_same<detail::decay_t<U>, in_place_t>::value &&
- !std::is_same<expected<T, E>, detail::decay_t<U>>::value &&
- !std::is_same<unexpected<E>, detail::decay_t<U>>::value>;
- template <class T, class E, class U, class G, class UR, class GR>
- using expected_enable_from_other = detail::enable_if_t<
- std::is_constructible<T, UR>::value &&
- std::is_constructible<E, GR>::value &&
- !std::is_constructible<T, expected<U, G> &>::value &&
- !std::is_constructible<T, expected<U, G> &&>::value &&
- !std::is_constructible<T, const expected<U, G> &>::value &&
- !std::is_constructible<T, const expected<U, G> &&>::value &&
- !std::is_convertible<expected<U, G> &, T>::value &&
- !std::is_convertible<expected<U, G> &&, T>::value &&
- !std::is_convertible<const expected<U, G> &, T>::value &&
- !std::is_convertible<const expected<U, G> &&, T>::value>;
- template <class T, class U>
- using is_void_or = conditional_t<std::is_void<T>::value, std::true_type, U>;
- template <class T>
- using is_copy_constructible_or_void =
- is_void_or<T, std::is_copy_constructible<T>>;
- template <class T>
- using is_move_constructible_or_void =
- is_void_or<T, std::is_move_constructible<T>>;
- template <class T>
- using is_copy_assignable_or_void = is_void_or<T, std::is_copy_assignable<T>>;
- template <class T>
- using is_move_assignable_or_void = is_void_or<T, std::is_move_assignable<T>>;
- } // namespace detail
- namespace detail {
- struct no_init_t {};
- static constexpr no_init_t no_init{};
- // Implements the storage of the values, and ensures that the destructor is
- // trivial if it can be.
- //
- // This specialization is for where neither `T` or `E` is trivially
- // destructible, so the destructors must be called on destruction of the
- // `expected`
- template <class T, class E, bool = std::is_trivially_destructible<T>::value,
- bool = std::is_trivially_destructible<E>::value>
- struct expected_storage_base {
- constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
- constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {}
- template <class... Args,
- detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
- nullptr>
- constexpr expected_storage_base(in_place_t, Args &&...args)
- : m_val(std::forward<Args>(args)...), m_has_val(true) {}
- template <class U, class... Args,
- detail::enable_if_t<std::is_constructible<
- T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
- constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
- Args &&...args)
- : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
- template <class... Args,
- detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
- nullptr>
- constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
- : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
- template <class U, class... Args,
- detail::enable_if_t<std::is_constructible<
- E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
- constexpr explicit expected_storage_base(unexpect_t,
- std::initializer_list<U> il,
- Args &&...args)
- : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
- ~expected_storage_base() {
- if (m_has_val) {
- m_val.~T();
- } else {
- m_unexpect.~unexpected<E>();
- }
- }
- union {
- T m_val;
- unexpected<E> m_unexpect;
- char m_no_init;
- };
- bool m_has_val;
- };
- // This specialization is for when both `T` and `E` are trivially-destructible,
- // so the destructor of the `expected` can be trivial.
- template <class T, class E> struct expected_storage_base<T, E, true, true> {
- constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
- constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {}
- template <class... Args,
- detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
- nullptr>
- constexpr expected_storage_base(in_place_t, Args &&...args)
- : m_val(std::forward<Args>(args)...), m_has_val(true) {}
- template <class U, class... Args,
- detail::enable_if_t<std::is_constructible<
- T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
- constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
- Args &&...args)
- : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
- template <class... Args,
- detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
- nullptr>
- constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
- : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
- template <class U, class... Args,
- detail::enable_if_t<std::is_constructible<
- E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
- constexpr explicit expected_storage_base(unexpect_t,
- std::initializer_list<U> il,
- Args &&...args)
- : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
- ~expected_storage_base() = default;
- union {
- T m_val;
- unexpected<E> m_unexpect;
- char m_no_init;
- };
- bool m_has_val;
- };
- // T is trivial, E is not.
- template <class T, class E> struct expected_storage_base<T, E, true, false> {
- constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
- TL_EXPECTED_MSVC2015_CONSTEXPR expected_storage_base(no_init_t)
- : m_no_init(), m_has_val(false) {}
- template <class... Args,
- detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
- nullptr>
- constexpr expected_storage_base(in_place_t, Args &&...args)
- : m_val(std::forward<Args>(args)...), m_has_val(true) {}
- template <class U, class... Args,
- detail::enable_if_t<std::is_constructible<
- T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
- constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
- Args &&...args)
- : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
- template <class... Args,
- detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
- nullptr>
- constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
- : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
- template <class U, class... Args,
- detail::enable_if_t<std::is_constructible<
- E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
- constexpr explicit expected_storage_base(unexpect_t,
- std::initializer_list<U> il,
- Args &&...args)
- : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
- ~expected_storage_base() {
- if (!m_has_val) {
- m_unexpect.~unexpected<E>();
- }
- }
- union {
- T m_val;
- unexpected<E> m_unexpect;
- char m_no_init;
- };
- bool m_has_val;
- };
- // E is trivial, T is not.
- template <class T, class E> struct expected_storage_base<T, E, false, true> {
- constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
- constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {}
- template <class... Args,
- detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
- nullptr>
- constexpr expected_storage_base(in_place_t, Args &&...args)
- : m_val(std::forward<Args>(args)...), m_has_val(true) {}
- template <class U, class... Args,
- detail::enable_if_t<std::is_constructible<
- T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
- constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
- Args &&...args)
- : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
- template <class... Args,
- detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
- nullptr>
- constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
- : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
- template <class U, class... Args,
- detail::enable_if_t<std::is_constructible<
- E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
- constexpr explicit expected_storage_base(unexpect_t,
- std::initializer_list<U> il,
- Args &&...args)
- : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
- ~expected_storage_base() {
- if (m_has_val) {
- m_val.~T();
- }
- }
- union {
- T m_val;
- unexpected<E> m_unexpect;
- char m_no_init;
- };
- bool m_has_val;
- };
- // `T` is `void`, `E` is trivially-destructible
- template <class E> struct expected_storage_base<void, E, false, true> {
- #if __GNUC__ <= 5
- //no constexpr for GCC 4/5 bug
- #else
- TL_EXPECTED_MSVC2015_CONSTEXPR
- #endif
- expected_storage_base() : m_has_val(true) {}
-
- constexpr expected_storage_base(no_init_t) : m_val(), m_has_val(false) {}
- constexpr expected_storage_base(in_place_t) : m_has_val(true) {}
- template <class... Args,
- detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
- nullptr>
- constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
- : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
- template <class U, class... Args,
- detail::enable_if_t<std::is_constructible<
- E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
- constexpr explicit expected_storage_base(unexpect_t,
- std::initializer_list<U> il,
- Args &&...args)
- : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
- ~expected_storage_base() = default;
- struct dummy {};
- union {
- unexpected<E> m_unexpect;
- dummy m_val;
- };
- bool m_has_val;
- };
- // `T` is `void`, `E` is not trivially-destructible
- template <class E> struct expected_storage_base<void, E, false, false> {
- constexpr expected_storage_base() : m_dummy(), m_has_val(true) {}
- constexpr expected_storage_base(no_init_t) : m_dummy(), m_has_val(false) {}
- constexpr expected_storage_base(in_place_t) : m_dummy(), m_has_val(true) {}
- template <class... Args,
- detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
- nullptr>
- constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
- : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
- template <class U, class... Args,
- detail::enable_if_t<std::is_constructible<
- E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
- constexpr explicit expected_storage_base(unexpect_t,
- std::initializer_list<U> il,
- Args &&...args)
- : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
- ~expected_storage_base() {
- if (!m_has_val) {
- m_unexpect.~unexpected<E>();
- }
- }
- union {
- unexpected<E> m_unexpect;
- char m_dummy;
- };
- bool m_has_val;
- };
- // This base class provides some handy member functions which can be used in
- // further derived classes
- template <class T, class E>
- struct expected_operations_base : expected_storage_base<T, E> {
- using expected_storage_base<T, E>::expected_storage_base;
- template <class... Args> void construct(Args &&...args) noexcept {
- new (std::addressof(this->m_val)) T(std::forward<Args>(args)...);
- this->m_has_val = true;
- }
- template <class Rhs> void construct_with(Rhs &&rhs) noexcept {
- new (std::addressof(this->m_val)) T(std::forward<Rhs>(rhs).get());
- this->m_has_val = true;
- }
- template <class... Args> void construct_error(Args &&...args) noexcept {
- new (std::addressof(this->m_unexpect))
- unexpected<E>(std::forward<Args>(args)...);
- this->m_has_val = false;
- }
- #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
- // These assign overloads ensure that the most efficient assignment
- // implementation is used while maintaining the strong exception guarantee.
- // The problematic case is where rhs has a value, but *this does not.
- //
- // This overload handles the case where we can just copy-construct `T`
- // directly into place without throwing.
- template <class U = T,
- detail::enable_if_t<std::is_nothrow_copy_constructible<U>::value>
- * = nullptr>
- void assign(const expected_operations_base &rhs) noexcept {
- if (!this->m_has_val && rhs.m_has_val) {
- geterr().~unexpected<E>();
- construct(rhs.get());
- } else {
- assign_common(rhs);
- }
- }
- // This overload handles the case where we can attempt to create a copy of
- // `T`, then no-throw move it into place if the copy was successful.
- template <class U = T,
- detail::enable_if_t<!std::is_nothrow_copy_constructible<U>::value &&
- std::is_nothrow_move_constructible<U>::value>
- * = nullptr>
- void assign(const expected_operations_base &rhs) noexcept {
- if (!this->m_has_val && rhs.m_has_val) {
- T tmp = rhs.get();
- geterr().~unexpected<E>();
- construct(std::move(tmp));
- } else {
- assign_common(rhs);
- }
- }
- // This overload is the worst-case, where we have to move-construct the
- // unexpected value into temporary storage, then try to copy the T into place.
- // If the construction succeeds, then everything is fine, but if it throws,
- // then we move the old unexpected value back into place before rethrowing the
- // exception.
- template <class U = T,
- detail::enable_if_t<!std::is_nothrow_copy_constructible<U>::value &&
- !std::is_nothrow_move_constructible<U>::value>
- * = nullptr>
- void assign(const expected_operations_base &rhs) {
- if (!this->m_has_val && rhs.m_has_val) {
- auto tmp = std::move(geterr());
- geterr().~unexpected<E>();
- #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
- try {
- construct(rhs.get());
- } catch (...) {
- geterr() = std::move(tmp);
- throw;
- }
- #else
- construct(rhs.get());
- #endif
- } else {
- assign_common(rhs);
- }
- }
- // These overloads do the same as above, but for rvalues
- template <class U = T,
- detail::enable_if_t<std::is_nothrow_move_constructible<U>::value>
- * = nullptr>
- void assign(expected_operations_base &&rhs) noexcept {
- if (!this->m_has_val && rhs.m_has_val) {
- geterr().~unexpected<E>();
- construct(std::move(rhs).get());
- } else {
- assign_common(std::move(rhs));
- }
- }
- template <class U = T,
- detail::enable_if_t<!std::is_nothrow_move_constructible<U>::value>
- * = nullptr>
- void assign(expected_operations_base &&rhs) {
- if (!this->m_has_val && rhs.m_has_val) {
- auto tmp = std::move(geterr());
- geterr().~unexpected<E>();
- #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
- try {
- construct(std::move(rhs).get());
- } catch (...) {
- geterr() = std::move(tmp);
- throw;
- }
- #else
- construct(std::move(rhs).get());
- #endif
- } else {
- assign_common(std::move(rhs));
- }
- }
- #else
- // If exceptions are disabled then we can just copy-construct
- void assign(const expected_operations_base &rhs) noexcept {
- if (!this->m_has_val && rhs.m_has_val) {
- geterr().~unexpected<E>();
- construct(rhs.get());
- } else {
- assign_common(rhs);
- }
- }
- void assign(expected_operations_base &&rhs) noexcept {
- if (!this->m_has_val && rhs.m_has_val) {
- geterr().~unexpected<E>();
- construct(std::move(rhs).get());
- } else {
- assign_common(std::move(rhs));
- }
- }
- #endif
- // The common part of move/copy assigning
- template <class Rhs> void assign_common(Rhs &&rhs) {
- if (this->m_has_val) {
- if (rhs.m_has_val) {
- get() = std::forward<Rhs>(rhs).get();
- } else {
- destroy_val();
- construct_error(std::forward<Rhs>(rhs).geterr());
- }
- } else {
- if (!rhs.m_has_val) {
- geterr() = std::forward<Rhs>(rhs).geterr();
- }
- }
- }
- bool has_value() const { return this->m_has_val; }
- TL_EXPECTED_11_CONSTEXPR T &get() & { return this->m_val; }
- constexpr const T &get() const & { return this->m_val; }
- TL_EXPECTED_11_CONSTEXPR T &&get() && { return std::move(this->m_val); }
- #ifndef TL_EXPECTED_NO_CONSTRR
- constexpr const T &&get() const && { return std::move(this->m_val); }
- #endif
- TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() & {
- return this->m_unexpect;
- }
- constexpr const unexpected<E> &geterr() const & { return this->m_unexpect; }
- TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() && {
- return std::move(this->m_unexpect);
- }
- #ifndef TL_EXPECTED_NO_CONSTRR
- constexpr const unexpected<E> &&geterr() const && {
- return std::move(this->m_unexpect);
- }
- #endif
- TL_EXPECTED_11_CONSTEXPR void destroy_val() { get().~T(); }
- };
- // This base class provides some handy member functions which can be used in
- // further derived classes
- template <class E>
- struct expected_operations_base<void, E> : expected_storage_base<void, E> {
- using expected_storage_base<void, E>::expected_storage_base;
- template <class... Args> void construct() noexcept { this->m_has_val = true; }
- // This function doesn't use its argument, but needs it so that code in
- // levels above this can work independently of whether T is void
- template <class Rhs> void construct_with(Rhs &&) noexcept {
- this->m_has_val = true;
- }
- template <class... Args> void construct_error(Args &&...args) noexcept {
- new (std::addressof(this->m_unexpect))
- unexpected<E>(std::forward<Args>(args)...);
- this->m_has_val = false;
- }
- template <class Rhs> void assign(Rhs &&rhs) noexcept {
- if (!this->m_has_val) {
- if (rhs.m_has_val) {
- geterr().~unexpected<E>();
- construct();
- } else {
- geterr() = std::forward<Rhs>(rhs).geterr();
- }
- } else {
- if (!rhs.m_has_val) {
- construct_error(std::forward<Rhs>(rhs).geterr());
- }
- }
- }
- bool has_value() const { return this->m_has_val; }
- TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() & {
- return this->m_unexpect;
- }
- constexpr const unexpected<E> &geterr() const & { return this->m_unexpect; }
- TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() && {
- return std::move(this->m_unexpect);
- }
- #ifndef TL_EXPECTED_NO_CONSTRR
- constexpr const unexpected<E> &&geterr() const && {
- return std::move(this->m_unexpect);
- }
- #endif
- TL_EXPECTED_11_CONSTEXPR void destroy_val() {
- // no-op
- }
- };
- // This class manages conditionally having a trivial copy constructor
- // This specialization is for when T and E are trivially copy constructible
- template <class T, class E,
- bool = is_void_or<T, TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T)>::
- value &&TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value>
- struct expected_copy_base : expected_operations_base<T, E> {
- using expected_operations_base<T, E>::expected_operations_base;
- };
- // This specialization is for when T or E are not trivially copy constructible
- template <class T, class E>
- struct expected_copy_base<T, E, false> : expected_operations_base<T, E> {
- using expected_operations_base<T, E>::expected_operations_base;
- expected_copy_base() = default;
- expected_copy_base(const expected_copy_base &rhs)
- : expected_operations_base<T, E>(no_init) {
- if (rhs.has_value()) {
- this->construct_with(rhs);
- } else {
- this->construct_error(rhs.geterr());
- }
- }
- expected_copy_base(expected_copy_base &&rhs) = default;
- expected_copy_base &operator=(const expected_copy_base &rhs) = default;
- expected_copy_base &operator=(expected_copy_base &&rhs) = default;
- };
- // This class manages conditionally having a trivial move constructor
- // Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it
- // doesn't implement an analogue to std::is_trivially_move_constructible. We
- // have to make do with a non-trivial move constructor even if T is trivially
- // move constructible
- #ifndef TL_EXPECTED_GCC49
- template <class T, class E,
- bool = is_void_or<T, std::is_trivially_move_constructible<T>>::value
- &&std::is_trivially_move_constructible<E>::value>
- struct expected_move_base : expected_copy_base<T, E> {
- using expected_copy_base<T, E>::expected_copy_base;
- };
- #else
- template <class T, class E, bool = false> struct expected_move_base;
- #endif
- template <class T, class E>
- struct expected_move_base<T, E, false> : expected_copy_base<T, E> {
- using expected_copy_base<T, E>::expected_copy_base;
- expected_move_base() = default;
- expected_move_base(const expected_move_base &rhs) = default;
- expected_move_base(expected_move_base &&rhs) noexcept(
- std::is_nothrow_move_constructible<T>::value)
- : expected_copy_base<T, E>(no_init) {
- if (rhs.has_value()) {
- this->construct_with(std::move(rhs));
- } else {
- this->construct_error(std::move(rhs.geterr()));
- }
- }
- expected_move_base &operator=(const expected_move_base &rhs) = default;
- expected_move_base &operator=(expected_move_base &&rhs) = default;
- };
- // This class manages conditionally having a trivial copy assignment operator
- template <class T, class E,
- bool = is_void_or<
- T, conjunction<TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T),
- TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T),
- TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T)>>::value
- &&TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(E)::value
- &&TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value
- &&TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(E)::value>
- struct expected_copy_assign_base : expected_move_base<T, E> {
- using expected_move_base<T, E>::expected_move_base;
- };
- template <class T, class E>
- struct expected_copy_assign_base<T, E, false> : expected_move_base<T, E> {
- using expected_move_base<T, E>::expected_move_base;
- expected_copy_assign_base() = default;
- expected_copy_assign_base(const expected_copy_assign_base &rhs) = default;
- expected_copy_assign_base(expected_copy_assign_base &&rhs) = default;
- expected_copy_assign_base &operator=(const expected_copy_assign_base &rhs) {
- this->assign(rhs);
- return *this;
- }
- expected_copy_assign_base &
- operator=(expected_copy_assign_base &&rhs) = default;
- };
- // This class manages conditionally having a trivial move assignment operator
- // Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it
- // doesn't implement an analogue to std::is_trivially_move_assignable. We have
- // to make do with a non-trivial move assignment operator even if T is trivially
- // move assignable
- #ifndef TL_EXPECTED_GCC49
- template <class T, class E,
- bool =
- is_void_or<T, conjunction<std::is_trivially_destructible<T>,
- std::is_trivially_move_constructible<T>,
- std::is_trivially_move_assignable<T>>>::
- value &&std::is_trivially_destructible<E>::value
- &&std::is_trivially_move_constructible<E>::value
- &&std::is_trivially_move_assignable<E>::value>
- struct expected_move_assign_base : expected_copy_assign_base<T, E> {
- using expected_copy_assign_base<T, E>::expected_copy_assign_base;
- };
- #else
- template <class T, class E, bool = false> struct expected_move_assign_base;
- #endif
- template <class T, class E>
- struct expected_move_assign_base<T, E, false>
- : expected_copy_assign_base<T, E> {
- using expected_copy_assign_base<T, E>::expected_copy_assign_base;
- expected_move_assign_base() = default;
- expected_move_assign_base(const expected_move_assign_base &rhs) = default;
- expected_move_assign_base(expected_move_assign_base &&rhs) = default;
- expected_move_assign_base &
- operator=(const expected_move_assign_base &rhs) = default;
- expected_move_assign_base &
- operator=(expected_move_assign_base &&rhs) noexcept(
- std::is_nothrow_move_constructible<T>::value
- &&std::is_nothrow_move_assignable<T>::value) {
- this->assign(std::move(rhs));
- return *this;
- }
- };
- // expected_delete_ctor_base will conditionally delete copy and move
- // constructors depending on whether T is copy/move constructible
- template <class T, class E,
- bool EnableCopy = (is_copy_constructible_or_void<T>::value &&
- std::is_copy_constructible<E>::value),
- bool EnableMove = (is_move_constructible_or_void<T>::value &&
- std::is_move_constructible<E>::value)>
- struct expected_delete_ctor_base {
- expected_delete_ctor_base() = default;
- expected_delete_ctor_base(const expected_delete_ctor_base &) = default;
- expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = default;
- expected_delete_ctor_base &
- operator=(const expected_delete_ctor_base &) = default;
- expected_delete_ctor_base &
- operator=(expected_delete_ctor_base &&) noexcept = default;
- };
- template <class T, class E>
- struct expected_delete_ctor_base<T, E, true, false> {
- expected_delete_ctor_base() = default;
- expected_delete_ctor_base(const expected_delete_ctor_base &) = default;
- expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = delete;
- expected_delete_ctor_base &
- operator=(const expected_delete_ctor_base &) = default;
- expected_delete_ctor_base &
- operator=(expected_delete_ctor_base &&) noexcept = default;
- };
- template <class T, class E>
- struct expected_delete_ctor_base<T, E, false, true> {
- expected_delete_ctor_base() = default;
- expected_delete_ctor_base(const expected_delete_ctor_base &) = delete;
- expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = default;
- expected_delete_ctor_base &
- operator=(const expected_delete_ctor_base &) = default;
- expected_delete_ctor_base &
- operator=(expected_delete_ctor_base &&) noexcept = default;
- };
- template <class T, class E>
- struct expected_delete_ctor_base<T, E, false, false> {
- expected_delete_ctor_base() = default;
- expected_delete_ctor_base(const expected_delete_ctor_base &) = delete;
- expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = delete;
- expected_delete_ctor_base &
- operator=(const expected_delete_ctor_base &) = default;
- expected_delete_ctor_base &
- operator=(expected_delete_ctor_base &&) noexcept = default;
- };
- // expected_delete_assign_base will conditionally delete copy and move
- // constructors depending on whether T and E are copy/move constructible +
- // assignable
- template <class T, class E,
- bool EnableCopy = (is_copy_constructible_or_void<T>::value &&
- std::is_copy_constructible<E>::value &&
- is_copy_assignable_or_void<T>::value &&
- std::is_copy_assignable<E>::value),
- bool EnableMove = (is_move_constructible_or_void<T>::value &&
- std::is_move_constructible<E>::value &&
- is_move_assignable_or_void<T>::value &&
- std::is_move_assignable<E>::value)>
- struct expected_delete_assign_base {
- expected_delete_assign_base() = default;
- expected_delete_assign_base(const expected_delete_assign_base &) = default;
- expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
- default;
- expected_delete_assign_base &
- operator=(const expected_delete_assign_base &) = default;
- expected_delete_assign_base &
- operator=(expected_delete_assign_base &&) noexcept = default;
- };
- template <class T, class E>
- struct expected_delete_assign_base<T, E, true, false> {
- expected_delete_assign_base() = default;
- expected_delete_assign_base(const expected_delete_assign_base &) = default;
- expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
- default;
- expected_delete_assign_base &
- operator=(const expected_delete_assign_base &) = default;
- expected_delete_assign_base &
- operator=(expected_delete_assign_base &&) noexcept = delete;
- };
- template <class T, class E>
- struct expected_delete_assign_base<T, E, false, true> {
- expected_delete_assign_base() = default;
- expected_delete_assign_base(const expected_delete_assign_base &) = default;
- expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
- default;
- expected_delete_assign_base &
- operator=(const expected_delete_assign_base &) = delete;
- expected_delete_assign_base &
- operator=(expected_delete_assign_base &&) noexcept = default;
- };
- template <class T, class E>
- struct expected_delete_assign_base<T, E, false, false> {
- expected_delete_assign_base() = default;
- expected_delete_assign_base(const expected_delete_assign_base &) = default;
- expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
- default;
- expected_delete_assign_base &
- operator=(const expected_delete_assign_base &) = delete;
- expected_delete_assign_base &
- operator=(expected_delete_assign_base &&) noexcept = delete;
- };
- // This is needed to be able to construct the expected_default_ctor_base which
- // follows, while still conditionally deleting the default constructor.
- struct default_constructor_tag {
- explicit constexpr default_constructor_tag() = default;
- };
- // expected_default_ctor_base will ensure that expected has a deleted default
- // consturctor if T is not default constructible.
- // This specialization is for when T is default constructible
- template <class T, class E,
- bool Enable =
- std::is_default_constructible<T>::value || std::is_void<T>::value>
- struct expected_default_ctor_base {
- constexpr expected_default_ctor_base() noexcept = default;
- constexpr expected_default_ctor_base(
- expected_default_ctor_base const &) noexcept = default;
- constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept =
- default;
- expected_default_ctor_base &
- operator=(expected_default_ctor_base const &) noexcept = default;
- expected_default_ctor_base &
- operator=(expected_default_ctor_base &&) noexcept = default;
- constexpr explicit expected_default_ctor_base(default_constructor_tag) {}
- };
- // This specialization is for when T is not default constructible
- template <class T, class E> struct expected_default_ctor_base<T, E, false> {
- constexpr expected_default_ctor_base() noexcept = delete;
- constexpr expected_default_ctor_base(
- expected_default_ctor_base const &) noexcept = default;
- constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept =
- default;
- expected_default_ctor_base &
- operator=(expected_default_ctor_base const &) noexcept = default;
- expected_default_ctor_base &
- operator=(expected_default_ctor_base &&) noexcept = default;
- constexpr explicit expected_default_ctor_base(default_constructor_tag) {}
- };
- } // namespace detail
- template <class E> class bad_expected_access : public std::exception {
- public:
- explicit bad_expected_access(E e) : m_val(std::move(e)) {}
- virtual const char *what() const noexcept override {
- return "Bad expected access";
- }
- const E &error() const & { return m_val; }
- E &error() & { return m_val; }
- const E &&error() const && { return std::move(m_val); }
- E &&error() && { return std::move(m_val); }
- private:
- E m_val;
- };
- /// An `expected<T, E>` object is an object that contains the storage for
- /// another object and manages the lifetime of this contained object `T`.
- /// Alternatively it could contain the storage for another unexpected object
- /// `E`. The contained object may not be initialized after the expected object
- /// has been initialized, and may not be destroyed before the expected object
- /// has been destroyed. The initialization state of the contained object is
- /// tracked by the expected object.
- template <class T, class E>
- class expected : private detail::expected_move_assign_base<T, E>,
- private detail::expected_delete_ctor_base<T, E>,
- private detail::expected_delete_assign_base<T, E>,
- private detail::expected_default_ctor_base<T, E> {
- static_assert(!std::is_reference<T>::value, "T must not be a reference");
- static_assert(!std::is_same<T, std::remove_cv<in_place_t>::type>::value,
- "T must not be in_place_t");
- static_assert(!std::is_same<T, std::remove_cv<unexpect_t>::type>::value,
- "T must not be unexpect_t");
- static_assert(
- !std::is_same<T, typename std::remove_cv<unexpected<E>>::type>::value,
- "T must not be unexpected<E>");
- static_assert(!std::is_reference<E>::value, "E must not be a reference");
- T *valptr() { return std::addressof(this->m_val); }
- const T *valptr() const { return std::addressof(this->m_val); }
- unexpected<E> *errptr() { return std::addressof(this->m_unexpect); }
- const unexpected<E> *errptr() const {
- return std::addressof(this->m_unexpect);
- }
- template <class U = T,
- detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
- TL_EXPECTED_11_CONSTEXPR U &val() {
- return this->m_val;
- }
- TL_EXPECTED_11_CONSTEXPR unexpected<E> &err() { return this->m_unexpect; }
- template <class U = T,
- detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
- constexpr const U &val() const {
- return this->m_val;
- }
- constexpr const unexpected<E> &err() const { return this->m_unexpect; }
- using impl_base = detail::expected_move_assign_base<T, E>;
- using ctor_base = detail::expected_default_ctor_base<T, E>;
- public:
- typedef T value_type;
- typedef E error_type;
- typedef unexpected<E> unexpected_type;
- #if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
- !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
- template <class F> TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) & {
- return and_then_impl(*this, std::forward<F>(f));
- }
- template <class F> TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) && {
- return and_then_impl(std::move(*this), std::forward<F>(f));
- }
- template <class F> constexpr auto and_then(F &&f) const & {
- return and_then_impl(*this, std::forward<F>(f));
- }
- #ifndef TL_EXPECTED_NO_CONSTRR
- template <class F> constexpr auto and_then(F &&f) const && {
- return and_then_impl(std::move(*this), std::forward<F>(f));
- }
- #endif
- #else
- template <class F>
- TL_EXPECTED_11_CONSTEXPR auto
- and_then(F &&f) & -> decltype(and_then_impl(std::declval<expected &>(),
- std::forward<F>(f))) {
- return and_then_impl(*this, std::forward<F>(f));
- }
- template <class F>
- TL_EXPECTED_11_CONSTEXPR auto
- and_then(F &&f) && -> decltype(and_then_impl(std::declval<expected &&>(),
- std::forward<F>(f))) {
- return and_then_impl(std::move(*this), std::forward<F>(f));
- }
- template <class F>
- constexpr auto and_then(F &&f) const & -> decltype(and_then_impl(
- std::declval<expected const &>(), std::forward<F>(f))) {
- return and_then_impl(*this, std::forward<F>(f));
- }
- #ifndef TL_EXPECTED_NO_CONSTRR
- template <class F>
- constexpr auto and_then(F &&f) const && -> decltype(and_then_impl(
- std::declval<expected const &&>(), std::forward<F>(f))) {
- return and_then_impl(std::move(*this), std::forward<F>(f));
- }
- #endif
- #endif
- #if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
- !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
- template <class F> TL_EXPECTED_11_CONSTEXPR auto map(F &&f) & {
- return expected_map_impl(*this, std::forward<F>(f));
- }
- template <class F> TL_EXPECTED_11_CONSTEXPR auto map(F &&f) && {
- return expected_map_impl(std::move(*this), std::forward<F>(f));
- }
- template <class F> constexpr auto map(F &&f) const & {
- return expected_map_impl(*this, std::forward<F>(f));
- }
- template <class F> constexpr auto map(F &&f) const && {
- return expected_map_impl(std::move(*this), std::forward<F>(f));
- }
- #else
- template <class F>
- TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(
- std::declval<expected &>(), std::declval<F &&>()))
- map(F &&f) & {
- return expected_map_impl(*this, std::forward<F>(f));
- }
- template <class F>
- TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval<expected>(),
- std::declval<F &&>()))
- map(F &&f) && {
- return expected_map_impl(std::move(*this), std::forward<F>(f));
- }
- template <class F>
- constexpr decltype(expected_map_impl(std::declval<const expected &>(),
- std::declval<F &&>()))
- map(F &&f) const & {
- return expected_map_impl(*this, std::forward<F>(f));
- }
- #ifndef TL_EXPECTED_NO_CONSTRR
- template <class F>
- constexpr decltype(expected_map_impl(std::declval<const expected &&>(),
- std::declval<F &&>()))
- map(F &&f) const && {
- return expected_map_impl(std::move(*this), std::forward<F>(f));
- }
- #endif
- #endif
- #if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
- !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
- template <class F> TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) & {
- return expected_map_impl(*this, std::forward<F>(f));
- }
- template <class F> TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) && {
- return expected_map_impl(std::move(*this), std::forward<F>(f));
- }
- template <class F> constexpr auto transform(F &&f) const & {
- return expected_map_impl(*this, std::forward<F>(f));
- }
- template <class F> constexpr auto transform(F &&f) const && {
- return expected_map_impl(std::move(*this), std::forward<F>(f));
- }
- #else
- template <class F>
- TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(
- std::declval<expected &>(), std::declval<F &&>()))
- transform(F &&f) & {
- return expected_map_impl(*this, std::forward<F>(f));
- }
- template <class F>
- TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval<expected>(),
- std::declval<F &&>()))
- transform(F &&f) && {
- return expected_map_impl(std::move(*this), std::forward<F>(f));
- }
- template <class F>
- constexpr decltype(expected_map_impl(std::declval<const expected &>(),
- std::declval<F &&>()))
- transform(F &&f) const & {
- return expected_map_impl(*this, std::forward<F>(f));
- }
- #ifndef TL_EXPECTED_NO_CONSTRR
- template <class F>
- constexpr decltype(expected_map_impl(std::declval<const expected &&>(),
- std::declval<F &&>()))
- transform(F &&f) const && {
- return expected_map_impl(std::move(*this), std::forward<F>(f));
- }
- #endif
- #endif
- #if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
- !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
- template <class F> TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) & {
- return map_error_impl(*this, std::forward<F>(f));
- }
- template <class F> TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) && {
- return map_error_impl(std::move(*this), std::forward<F>(f));
- }
- template <class F> constexpr auto map_error(F &&f) const & {
- return map_error_impl(*this, std::forward<F>(f));
- }
- template <class F> constexpr auto map_error(F &&f) const && {
- return map_error_impl(std::move(*this), std::forward<F>(f));
- }
- #else
- template <class F>
- TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &>(),
- std::declval<F &&>()))
- map_error(F &&f) & {
- return map_error_impl(*this, std::forward<F>(f));
- }
- template <class F>
- TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &&>(),
- std::declval<F &&>()))
- map_error(F &&f) && {
- return map_error_impl(std::move(*this), std::forward<F>(f));
- }
- template <class F>
- constexpr decltype(map_error_impl(std::declval<const expected &>(),
- std::declval<F &&>()))
- map_error(F &&f) const & {
- return map_error_impl(*this, std::forward<F>(f));
- }
- #ifndef TL_EXPECTED_NO_CONSTRR
- template <class F>
- constexpr decltype(map_error_impl(std::declval<const expected &&>(),
- std::declval<F &&>()))
- map_error(F &&f) const && {
- return map_error_impl(std::move(*this), std::forward<F>(f));
- }
- #endif
- #endif
- #if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
- !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
- template <class F> TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) & {
- return map_error_impl(*this, std::forward<F>(f));
- }
- template <class F> TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) && {
- return map_error_impl(std::move(*this), std::forward<F>(f));
- }
- template <class F> constexpr auto transform_error(F &&f) const & {
- return map_error_impl(*this, std::forward<F>(f));
- }
- template <class F> constexpr auto transform_error(F &&f) const && {
- return map_error_impl(std::move(*this), std::forward<F>(f));
- }
- #else
- template <class F>
- TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &>(),
- std::declval<F &&>()))
- transform_error(F &&f) & {
- return map_error_impl(*this, std::forward<F>(f));
- }
- template <class F>
- TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &&>(),
- std::declval<F &&>()))
- transform_error(F &&f) && {
- return map_error_impl(std::move(*this), std::forward<F>(f));
- }
- template <class F>
- constexpr decltype(map_error_impl(std::declval<const expected &>(),
- std::declval<F &&>()))
- transform_error(F &&f) const & {
- return map_error_impl(*this, std::forward<F>(f));
- }
- #ifndef TL_EXPECTED_NO_CONSTRR
- template <class F>
- constexpr decltype(map_error_impl(std::declval<const expected &&>(),
- std::declval<F &&>()))
- transform_error(F &&f) const && {
- return map_error_impl(std::move(*this), std::forward<F>(f));
- }
- #endif
- #endif
- template <class F> expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) & {
- return or_else_impl(*this, std::forward<F>(f));
- }
- template <class F> expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) && {
- return or_else_impl(std::move(*this), std::forward<F>(f));
- }
- template <class F> expected constexpr or_else(F &&f) const & {
- return or_else_impl(*this, std::forward<F>(f));
- }
- #ifndef TL_EXPECTED_NO_CONSTRR
- template <class F> expected constexpr or_else(F &&f) const && {
- return or_else_impl(std::move(*this), std::forward<F>(f));
- }
- #endif
- constexpr expected() = default;
- constexpr expected(const expected &rhs) = default;
- constexpr expected(expected &&rhs) = default;
- expected &operator=(const expected &rhs) = default;
- expected &operator=(expected &&rhs) = default;
- template <class... Args,
- detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
- nullptr>
- constexpr expected(in_place_t, Args &&...args)
- : impl_base(in_place, std::forward<Args>(args)...),
- ctor_base(detail::default_constructor_tag{}) {}
- template <class U, class... Args,
- detail::enable_if_t<std::is_constructible<
- T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
- constexpr expected(in_place_t, std::initializer_list<U> il, Args &&...args)
- : impl_base(in_place, il, std::forward<Args>(args)...),
- ctor_base(detail::default_constructor_tag{}) {}
- template <class G = E,
- detail::enable_if_t<std::is_constructible<E, const G &>::value> * =
- nullptr,
- detail::enable_if_t<!std::is_convertible<const G &, E>::value> * =
- nullptr>
- explicit constexpr expected(const unexpected<G> &e)
- : impl_base(unexpect, e.value()),
- ctor_base(detail::default_constructor_tag{}) {}
- template <
- class G = E,
- detail::enable_if_t<std::is_constructible<E, const G &>::value> * =
- nullptr,
- detail::enable_if_t<std::is_convertible<const G &, E>::value> * = nullptr>
- constexpr expected(unexpected<G> const &e)
- : impl_base(unexpect, e.value()),
- ctor_base(detail::default_constructor_tag{}) {}
- template <
- class G = E,
- detail::enable_if_t<std::is_constructible<E, G &&>::value> * = nullptr,
- detail::enable_if_t<!std::is_convertible<G &&, E>::value> * = nullptr>
- explicit constexpr expected(unexpected<G> &&e) noexcept(
- std::is_nothrow_constructible<E, G &&>::value)
- : impl_base(unexpect, std::move(e.value())),
- ctor_base(detail::default_constructor_tag{}) {}
- template <
- class G = E,
- detail::enable_if_t<std::is_constructible<E, G &&>::value> * = nullptr,
- detail::enable_if_t<std::is_convertible<G &&, E>::value> * = nullptr>
- constexpr expected(unexpected<G> &&e) noexcept(
- std::is_nothrow_constructible<E, G &&>::value)
- : impl_base(unexpect, std::move(e.value())),
- ctor_base(detail::default_constructor_tag{}) {}
- template <class... Args,
- detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
- nullptr>
- constexpr explicit expected(unexpect_t, Args &&...args)
- : impl_base(unexpect, std::forward<Args>(args)...),
- ctor_base(detail::default_constructor_tag{}) {}
- template <class U, class... Args,
- detail::enable_if_t<std::is_constructible<
- E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
- constexpr explicit expected(unexpect_t, std::initializer_list<U> il,
- Args &&...args)
- : impl_base(unexpect, il, std::forward<Args>(args)...),
- ctor_base(detail::default_constructor_tag{}) {}
- template <class U, class G,
- detail::enable_if_t<!(std::is_convertible<U const &, T>::value &&
- std::is_convertible<G const &, E>::value)> * =
- nullptr,
- detail::expected_enable_from_other<T, E, U, G, const U &, const G &>
- * = nullptr>
- explicit TL_EXPECTED_11_CONSTEXPR expected(const expected<U, G> &rhs)
- : ctor_base(detail::default_constructor_tag{}) {
- if (rhs.has_value()) {
- this->construct(*rhs);
- } else {
- this->construct_error(rhs.error());
- }
- }
- template <class U, class G,
- detail::enable_if_t<(std::is_convertible<U const &, T>::value &&
- std::is_convertible<G const &, E>::value)> * =
- nullptr,
- detail::expected_enable_from_other<T, E, U, G, const U &, const G &>
- * = nullptr>
- TL_EXPECTED_11_CONSTEXPR expected(const expected<U, G> &rhs)
- : ctor_base(detail::default_constructor_tag{}) {
- if (rhs.has_value()) {
- this->construct(*rhs);
- } else {
- this->construct_error(rhs.error());
- }
- }
- template <
- class U, class G,
- detail::enable_if_t<!(std::is_convertible<U &&, T>::value &&
- std::is_convertible<G &&, E>::value)> * = nullptr,
- detail::expected_enable_from_other<T, E, U, G, U &&, G &&> * = nullptr>
- explicit TL_EXPECTED_11_CONSTEXPR expected(expected<U, G> &&rhs)
- : ctor_base(detail::default_constructor_tag{}) {
- if (rhs.has_value()) {
- this->construct(std::move(*rhs));
- } else {
- this->construct_error(std::move(rhs.error()));
- }
- }
- template <
- class U, class G,
- detail::enable_if_t<(std::is_convertible<U &&, T>::value &&
- std::is_convertible<G &&, E>::value)> * = nullptr,
- detail::expected_enable_from_other<T, E, U, G, U &&, G &&> * = nullptr>
- TL_EXPECTED_11_CONSTEXPR expected(expected<U, G> &&rhs)
- : ctor_base(detail::default_constructor_tag{}) {
- if (rhs.has_value()) {
- this->construct(std::move(*rhs));
- } else {
- this->construct_error(std::move(rhs.error()));
- }
- }
- template <
- class U = T,
- detail::enable_if_t<!std::is_convertible<U &&, T>::value> * = nullptr,
- detail::expected_enable_forward_value<T, E, U> * = nullptr>
- explicit TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v)
- : expected(in_place, std::forward<U>(v)) {}
- template <
- class U = T,
- detail::enable_if_t<std::is_convertible<U &&, T>::value> * = nullptr,
- detail::expected_enable_forward_value<T, E, U> * = nullptr>
- TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v)
- : expected(in_place, std::forward<U>(v)) {}
- template <
- class U = T, class G = T,
- detail::enable_if_t<std::is_nothrow_constructible<T, U &&>::value> * =
- nullptr,
- detail::enable_if_t<!std::is_void<G>::value> * = nullptr,
- detail::enable_if_t<
- (!std::is_same<expected<T, E>, detail::decay_t<U>>::value &&
- !detail::conjunction<std::is_scalar<T>,
- std::is_same<T, detail::decay_t<U>>>::value &&
- std::is_constructible<T, U>::value &&
- std::is_assignable<G &, U>::value &&
- std::is_nothrow_move_constructible<E>::value)> * = nullptr>
- expected &operator=(U &&v) {
- if (has_value()) {
- val() = std::forward<U>(v);
- } else {
- err().~unexpected<E>();
- ::new (valptr()) T(std::forward<U>(v));
- this->m_has_val = true;
- }
- return *this;
- }
- template <
- class U = T, class G = T,
- detail::enable_if_t<!std::is_nothrow_constructible<T, U &&>::value> * =
- nullptr,
- detail::enable_if_t<!std::is_void<U>::value> * = nullptr,
- detail::enable_if_t<
- (!std::is_same<expected<T, E>, detail::decay_t<U>>::value &&
- !detail::conjunction<std::is_scalar<T>,
- std::is_same<T, detail::decay_t<U>>>::value &&
- std::is_constructible<T, U>::value &&
- std::is_assignable<G &, U>::value &&
- std::is_nothrow_move_constructible<E>::value)> * = nullptr>
- expected &operator=(U &&v) {
- if (has_value()) {
- val() = std::forward<U>(v);
- } else {
- auto tmp = std::move(err());
- err().~unexpected<E>();
- #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
- try {
- ::new (valptr()) T(std::forward<U>(v));
- this->m_has_val = true;
- } catch (...) {
- err() = std::move(tmp);
- throw;
- }
- #else
- ::new (valptr()) T(std::forward<U>(v));
- this->m_has_val = true;
- #endif
- }
- return *this;
- }
- template <class G = E,
- detail::enable_if_t<std::is_nothrow_copy_constructible<G>::value &&
- std::is_assignable<G &, G>::value> * = nullptr>
- expected &operator=(const unexpected<G> &rhs) {
- if (!has_value()) {
- err() = rhs;
- } else {
- this->destroy_val();
- ::new (errptr()) unexpected<E>(rhs);
- this->m_has_val = false;
- }
- return *this;
- }
- template <class G = E,
- detail::enable_if_t<std::is_nothrow_move_constructible<G>::value &&
- std::is_move_assignable<G>::value> * = nullptr>
- expected &operator=(unexpected<G> &&rhs) noexcept {
- if (!has_value()) {
- err() = std::move(rhs);
- } else {
- this->destroy_val();
- ::new (errptr()) unexpected<E>(std::move(rhs));
- this->m_has_val = false;
- }
- return *this;
- }
- template <class... Args, detail::enable_if_t<std::is_nothrow_constructible<
- T, Args &&...>::value> * = nullptr>
- void emplace(Args &&...args) {
- if (has_value()) {
- val().~T();
- } else {
- err().~unexpected<E>();
- this->m_has_val = true;
- }
- ::new (valptr()) T(std::forward<Args>(args)...);
- }
- template <class... Args, detail::enable_if_t<!std::is_nothrow_constructible<
- T, Args &&...>::value> * = nullptr>
- void emplace(Args &&...args) {
- if (has_value()) {
- val().~T();
- ::new (valptr()) T(std::forward<Args>(args)...);
- } else {
- auto tmp = std::move(err());
- err().~unexpected<E>();
- #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
- try {
- ::new (valptr()) T(std::forward<Args>(args)...);
- this->m_has_val = true;
- } catch (...) {
- err() = std::move(tmp);
- throw;
- }
- #else
- ::new (valptr()) T(std::forward<Args>(args)...);
- this->m_has_val = true;
- #endif
- }
- }
- template <class U, class... Args,
- detail::enable_if_t<std::is_nothrow_constructible<
- T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
- void emplace(std::initializer_list<U> il, Args &&...args) {
- if (has_value()) {
- T t(il, std::forward<Args>(args)...);
- val() = std::move(t);
- } else {
- err().~unexpected<E>();
- ::new (valptr()) T(il, std::forward<Args>(args)...);
- this->m_has_val = true;
- }
- }
- template <class U, class... Args,
- detail::enable_if_t<!std::is_nothrow_constructible<
- T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
- void emplace(std::initializer_list<U> il, Args &&...args) {
- if (has_value()) {
- T t(il, std::forward<Args>(args)...);
- val() = std::move(t);
- } else {
- auto tmp = std::move(err());
- err().~unexpected<E>();
- #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
- try {
- ::new (valptr()) T(il, std::forward<Args>(args)...);
- this->m_has_val = true;
- } catch (...) {
- err() = std::move(tmp);
- throw;
- }
- #else
- ::new (valptr()) T(il, std::forward<Args>(args)...);
- this->m_has_val = true;
- #endif
- }
- }
- private:
- using t_is_void = std::true_type;
- using t_is_not_void = std::false_type;
- using t_is_nothrow_move_constructible = std::true_type;
- using move_constructing_t_can_throw = std::false_type;
- using e_is_nothrow_move_constructible = std::true_type;
- using move_constructing_e_can_throw = std::false_type;
- void swap_where_both_have_value(expected & /*rhs*/, t_is_void) noexcept {
- // swapping void is a no-op
- }
- void swap_where_both_have_value(expected &rhs, t_is_not_void) {
- using std::swap;
- swap(val(), rhs.val());
- }
- void swap_where_only_one_has_value(expected &rhs, t_is_void) noexcept(
- std::is_nothrow_move_constructible<E>::value) {
- ::new (errptr()) unexpected_type(std::move(rhs.err()));
- rhs.err().~unexpected_type();
- std::swap(this->m_has_val, rhs.m_has_val);
- }
- void swap_where_only_one_has_value(expected &rhs, t_is_not_void) {
- swap_where_only_one_has_value_and_t_is_not_void(
- rhs, typename std::is_nothrow_move_constructible<T>::type{},
- typename std::is_nothrow_move_constructible<E>::type{});
- }
- void swap_where_only_one_has_value_and_t_is_not_void(
- expected &rhs, t_is_nothrow_move_constructible,
- e_is_nothrow_move_constructible) noexcept {
- auto temp = std::move(val());
- val().~T();
- ::new (errptr()) unexpected_type(std::move(rhs.err()));
- rhs.err().~unexpected_type();
- ::new (rhs.valptr()) T(std::move(temp));
- std::swap(this->m_has_val, rhs.m_has_val);
- }
- void swap_where_only_one_has_value_and_t_is_not_void(
- expected &rhs, t_is_nothrow_move_constructible,
- move_constructing_e_can_throw) {
- auto temp = std::move(val());
- val().~T();
- #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
- try {
- ::new (errptr()) unexpected_type(std::move(rhs.err()));
- rhs.err().~unexpected_type();
- ::new (rhs.valptr()) T(std::move(temp));
- std::swap(this->m_has_val, rhs.m_has_val);
- } catch (...) {
- val() = std::move(temp);
- throw;
- }
- #else
- ::new (errptr()) unexpected_type(std::move(rhs.err()));
- rhs.err().~unexpected_type();
- ::new (rhs.valptr()) T(std::move(temp));
- std::swap(this->m_has_val, rhs.m_has_val);
- #endif
- }
- void swap_where_only_one_has_value_and_t_is_not_void(
- expected &rhs, move_constructing_t_can_throw,
- e_is_nothrow_move_constructible) {
- auto temp = std::move(rhs.err());
- rhs.err().~unexpected_type();
- #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
- try {
- ::new (rhs.valptr()) T(std::move(val()));
- val().~T();
- ::new (errptr()) unexpected_type(std::move(temp));
- std::swap(this->m_has_val, rhs.m_has_val);
- } catch (...) {
- rhs.err() = std::move(temp);
- throw;
- }
- #else
- ::new (rhs.valptr()) T(std::move(val()));
- val().~T();
- ::new (errptr()) unexpected_type(std::move(temp));
- std::swap(this->m_has_val, rhs.m_has_val);
- #endif
- }
- public:
- template <class OT = T, class OE = E>
- detail::enable_if_t<detail::is_swappable<OT>::value &&
- detail::is_swappable<OE>::value &&
- (std::is_nothrow_move_constructible<OT>::value ||
- std::is_nothrow_move_constructible<OE>::value)>
- swap(expected &rhs) noexcept(
- std::is_nothrow_move_constructible<T>::value
- &&detail::is_nothrow_swappable<T>::value
- &&std::is_nothrow_move_constructible<E>::value
- &&detail::is_nothrow_swappable<E>::value) {
- if (has_value() && rhs.has_value()) {
- swap_where_both_have_value(rhs, typename std::is_void<T>::type{});
- } else if (!has_value() && rhs.has_value()) {
- rhs.swap(*this);
- } else if (has_value()) {
- swap_where_only_one_has_value(rhs, typename std::is_void<T>::type{});
- } else {
- using std::swap;
- swap(err(), rhs.err());
- }
- }
- constexpr const T *operator->() const {
- TL_ASSERT(has_value());
- return valptr();
- }
- TL_EXPECTED_11_CONSTEXPR T *operator->() {
- TL_ASSERT(has_value());
- return valptr();
- }
- template <class U = T,
- detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
- constexpr const U &operator*() const & {
- TL_ASSERT(has_value());
- return val();
- }
- template <class U = T,
- detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
- TL_EXPECTED_11_CONSTEXPR U &operator*() & {
- TL_ASSERT(has_value());
- return val();
- }
- template <class U = T,
- detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
- constexpr const U &&operator*() const && {
- TL_ASSERT(has_value());
- return std::move(val());
- }
- template <class U = T,
- detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
- TL_EXPECTED_11_CONSTEXPR U &&operator*() && {
- TL_ASSERT(has_value());
- return std::move(val());
- }
- constexpr bool has_value() const noexcept { return this->m_has_val; }
- constexpr explicit operator bool() const noexcept { return this->m_has_val; }
- template <class U = T,
- detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
- TL_EXPECTED_11_CONSTEXPR const U &value() const & {
- if (!has_value())
- detail::throw_exception(bad_expected_access<E>(err().value()));
- return val();
- }
- template <class U = T,
- detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
- TL_EXPECTED_11_CONSTEXPR U &value() & {
- if (!has_value())
- detail::throw_exception(bad_expected_access<E>(err().value()));
- return val();
- }
- template <class U = T,
- detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
- TL_EXPECTED_11_CONSTEXPR const U &&value() const && {
- if (!has_value())
- detail::throw_exception(bad_expected_access<E>(std::move(err()).value()));
- return std::move(val());
- }
- template <class U = T,
- detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
- TL_EXPECTED_11_CONSTEXPR U &&value() && {
- if (!has_value())
- detail::throw_exception(bad_expected_access<E>(std::move(err()).value()));
- return std::move(val());
- }
- constexpr const E &error() const & {
- TL_ASSERT(!has_value());
- return err().value();
- }
- TL_EXPECTED_11_CONSTEXPR E &error() & {
- TL_ASSERT(!has_value());
- return err().value();
- }
- constexpr const E &&error() const && {
- TL_ASSERT(!has_value());
- return std::move(err().value());
- }
- TL_EXPECTED_11_CONSTEXPR E &&error() && {
- TL_ASSERT(!has_value());
- return std::move(err().value());
- }
- template <class U> constexpr T value_or(U &&v) const & {
- static_assert(std::is_copy_constructible<T>::value &&
- std::is_convertible<U &&, T>::value,
- "T must be copy-constructible and convertible to from U&&");
- return bool(*this) ? **this : static_cast<T>(std::forward<U>(v));
- }
- template <class U> TL_EXPECTED_11_CONSTEXPR T value_or(U &&v) && {
- static_assert(std::is_move_constructible<T>::value &&
- std::is_convertible<U &&, T>::value,
- "T must be move-constructible and convertible to from U&&");
- return bool(*this) ? std::move(**this) : static_cast<T>(std::forward<U>(v));
- }
- };
- namespace detail {
- template <class Exp> using exp_t = typename detail::decay_t<Exp>::value_type;
- template <class Exp> using err_t = typename detail::decay_t<Exp>::error_type;
- template <class Exp, class Ret> using ret_t = expected<Ret, err_t<Exp>>;
- #ifdef TL_EXPECTED_CXX14
- template <class Exp, class F,
- detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
- class Ret = decltype(detail::invoke(std::declval<F>(),
- *std::declval<Exp>()))>
- constexpr auto and_then_impl(Exp &&exp, F &&f) {
- static_assert(detail::is_expected<Ret>::value, "F must return an expected");
- return exp.has_value()
- ? detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp))
- : Ret(unexpect, std::forward<Exp>(exp).error());
- }
- template <class Exp, class F,
- detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
- class Ret = decltype(detail::invoke(std::declval<F>()))>
- constexpr auto and_then_impl(Exp &&exp, F &&f) {
- static_assert(detail::is_expected<Ret>::value, "F must return an expected");
- return exp.has_value() ? detail::invoke(std::forward<F>(f))
- : Ret(unexpect, std::forward<Exp>(exp).error());
- }
- #else
- template <class> struct TC;
- template <class Exp, class F,
- class Ret = decltype(detail::invoke(std::declval<F>(),
- *std::declval<Exp>())),
- detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr>
- auto and_then_impl(Exp &&exp, F &&f) -> Ret {
- static_assert(detail::is_expected<Ret>::value, "F must return an expected");
- return exp.has_value()
- ? detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp))
- : Ret(unexpect, std::forward<Exp>(exp).error());
- }
- template <class Exp, class F,
- class Ret = decltype(detail::invoke(std::declval<F>())),
- detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr>
- constexpr auto and_then_impl(Exp &&exp, F &&f) -> Ret {
- static_assert(detail::is_expected<Ret>::value, "F must return an expected");
- return exp.has_value() ? detail::invoke(std::forward<F>(f))
- : Ret(unexpect, std::forward<Exp>(exp).error());
- }
- #endif
- #ifdef TL_EXPECTED_CXX14
- template <class Exp, class F,
- detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
- class Ret = decltype(detail::invoke(std::declval<F>(),
- *std::declval<Exp>())),
- detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
- constexpr auto expected_map_impl(Exp &&exp, F &&f) {
- using result = ret_t<Exp, detail::decay_t<Ret>>;
- return exp.has_value() ? result(detail::invoke(std::forward<F>(f),
- *std::forward<Exp>(exp)))
- : result(unexpect, std::forward<Exp>(exp).error());
- }
- template <class Exp, class F,
- detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
- class Ret = decltype(detail::invoke(std::declval<F>(),
- *std::declval<Exp>())),
- detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
- auto expected_map_impl(Exp &&exp, F &&f) {
- using result = expected<void, err_t<Exp>>;
- if (exp.has_value()) {
- detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp));
- return result();
- }
- return result(unexpect, std::forward<Exp>(exp).error());
- }
- template <class Exp, class F,
- detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
- class Ret = decltype(detail::invoke(std::declval<F>())),
- detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
- constexpr auto expected_map_impl(Exp &&exp, F &&f) {
- using result = ret_t<Exp, detail::decay_t<Ret>>;
- return exp.has_value() ? result(detail::invoke(std::forward<F>(f)))
- : result(unexpect, std::forward<Exp>(exp).error());
- }
- template <class Exp, class F,
- detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
- class Ret = decltype(detail::invoke(std::declval<F>())),
- detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
- auto expected_map_impl(Exp &&exp, F &&f) {
- using result = expected<void, err_t<Exp>>;
- if (exp.has_value()) {
- detail::invoke(std::forward<F>(f));
- return result();
- }
- return result(unexpect, std::forward<Exp>(exp).error());
- }
- #else
- template <class Exp, class F,
- detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
- class Ret = decltype(detail::invoke(std::declval<F>(),
- *std::declval<Exp>())),
- detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
- constexpr auto expected_map_impl(Exp &&exp, F &&f)
- -> ret_t<Exp, detail::decay_t<Ret>> {
- using result = ret_t<Exp, detail::decay_t<Ret>>;
- return exp.has_value() ? result(detail::invoke(std::forward<F>(f),
- *std::forward<Exp>(exp)))
- : result(unexpect, std::forward<Exp>(exp).error());
- }
- template <class Exp, class F,
- detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
- class Ret = decltype(detail::invoke(std::declval<F>(),
- *std::declval<Exp>())),
- detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
- auto expected_map_impl(Exp &&exp, F &&f) -> expected<void, err_t<Exp>> {
- if (exp.has_value()) {
- detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp));
- return {};
- }
- return unexpected<err_t<Exp>>(std::forward<Exp>(exp).error());
- }
- template <class Exp, class F,
- detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
- class Ret = decltype(detail::invoke(std::declval<F>())),
- detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
- constexpr auto expected_map_impl(Exp &&exp, F &&f)
- -> ret_t<Exp, detail::decay_t<Ret>> {
- using result = ret_t<Exp, detail::decay_t<Ret>>;
- return exp.has_value() ? result(detail::invoke(std::forward<F>(f)))
- : result(unexpect, std::forward<Exp>(exp).error());
- }
- template <class Exp, class F,
- detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
- class Ret = decltype(detail::invoke(std::declval<F>())),
- detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
- auto expected_map_impl(Exp &&exp, F &&f) -> expected<void, err_t<Exp>> {
- if (exp.has_value()) {
- detail::invoke(std::forward<F>(f));
- return {};
- }
- return unexpected<err_t<Exp>>(std::forward<Exp>(exp).error());
- }
- #endif
- #if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
- !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
- template <class Exp, class F,
- detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
- class Ret = decltype(detail::invoke(std::declval<F>(),
- std::declval<Exp>().error())),
- detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
- constexpr auto map_error_impl(Exp &&exp, F &&f) {
- using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
- return exp.has_value()
- ? result(*std::forward<Exp>(exp))
- : result(unexpect, detail::invoke(std::forward<F>(f),
- std::forward<Exp>(exp).error()));
- }
- template <class Exp, class F,
- detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
- class Ret = decltype(detail::invoke(std::declval<F>(),
- std::declval<Exp>().error())),
- detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
- auto map_error_impl(Exp &&exp, F &&f) {
- using result = expected<exp_t<Exp>, monostate>;
- if (exp.has_value()) {
- return result(*std::forward<Exp>(exp));
- }
- detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
- return result(unexpect, monostate{});
- }
- template <class Exp, class F,
- detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
- class Ret = decltype(detail::invoke(std::declval<F>(),
- std::declval<Exp>().error())),
- detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
- constexpr auto map_error_impl(Exp &&exp, F &&f) {
- using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
- return exp.has_value()
- ? result()
- : result(unexpect, detail::invoke(std::forward<F>(f),
- std::forward<Exp>(exp).error()));
- }
- template <class Exp, class F,
- detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
- class Ret = decltype(detail::invoke(std::declval<F>(),
- std::declval<Exp>().error())),
- detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
- auto map_error_impl(Exp &&exp, F &&f) {
- using result = expected<exp_t<Exp>, monostate>;
- if (exp.has_value()) {
- return result();
- }
- detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
- return result(unexpect, monostate{});
- }
- #else
- template <class Exp, class F,
- detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
- class Ret = decltype(detail::invoke(std::declval<F>(),
- std::declval<Exp>().error())),
- detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
- constexpr auto map_error_impl(Exp &&exp, F &&f)
- -> expected<exp_t<Exp>, detail::decay_t<Ret>> {
- using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
- return exp.has_value()
- ? result(*std::forward<Exp>(exp))
- : result(unexpect, detail::invoke(std::forward<F>(f),
- std::forward<Exp>(exp).error()));
- }
- template <class Exp, class F,
- detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
- class Ret = decltype(detail::invoke(std::declval<F>(),
- std::declval<Exp>().error())),
- detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
- auto map_error_impl(Exp &&exp, F &&f) -> expected<exp_t<Exp>, monostate> {
- using result = expected<exp_t<Exp>, monostate>;
- if (exp.has_value()) {
- return result(*std::forward<Exp>(exp));
- }
- detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
- return result(unexpect, monostate{});
- }
- template <class Exp, class F,
- detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
- class Ret = decltype(detail::invoke(std::declval<F>(),
- std::declval<Exp>().error())),
- detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
- constexpr auto map_error_impl(Exp &&exp, F &&f)
- -> expected<exp_t<Exp>, detail::decay_t<Ret>> {
- using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
- return exp.has_value()
- ? result()
- : result(unexpect, detail::invoke(std::forward<F>(f),
- std::forward<Exp>(exp).error()));
- }
- template <class Exp, class F,
- detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
- class Ret = decltype(detail::invoke(std::declval<F>(),
- std::declval<Exp>().error())),
- detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
- auto map_error_impl(Exp &&exp, F &&f) -> expected<exp_t<Exp>, monostate> {
- using result = expected<exp_t<Exp>, monostate>;
- if (exp.has_value()) {
- return result();
- }
- detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
- return result(unexpect, monostate{});
- }
- #endif
- #ifdef TL_EXPECTED_CXX14
- template <class Exp, class F,
- class Ret = decltype(detail::invoke(std::declval<F>(),
- std::declval<Exp>().error())),
- detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
- constexpr auto or_else_impl(Exp &&exp, F &&f) {
- static_assert(detail::is_expected<Ret>::value, "F must return an expected");
- return exp.has_value() ? std::forward<Exp>(exp)
- : detail::invoke(std::forward<F>(f),
- std::forward<Exp>(exp).error());
- }
- template <class Exp, class F,
- class Ret = decltype(detail::invoke(std::declval<F>(),
- std::declval<Exp>().error())),
- detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
- detail::decay_t<Exp> or_else_impl(Exp &&exp, F &&f) {
- return exp.has_value() ? std::forward<Exp>(exp)
- : (detail::invoke(std::forward<F>(f),
- std::forward<Exp>(exp).error()),
- std::forward<Exp>(exp));
- }
- #else
- template <class Exp, class F,
- class Ret = decltype(detail::invoke(std::declval<F>(),
- std::declval<Exp>().error())),
- detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
- auto or_else_impl(Exp &&exp, F &&f) -> Ret {
- static_assert(detail::is_expected<Ret>::value, "F must return an expected");
- return exp.has_value() ? std::forward<Exp>(exp)
- : detail::invoke(std::forward<F>(f),
- std::forward<Exp>(exp).error());
- }
- template <class Exp, class F,
- class Ret = decltype(detail::invoke(std::declval<F>(),
- std::declval<Exp>().error())),
- detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
- detail::decay_t<Exp> or_else_impl(Exp &&exp, F &&f) {
- return exp.has_value() ? std::forward<Exp>(exp)
- : (detail::invoke(std::forward<F>(f),
- std::forward<Exp>(exp).error()),
- std::forward<Exp>(exp));
- }
- #endif
- } // namespace detail
- template <class T, class E, class U, class F>
- constexpr bool operator==(const expected<T, E> &lhs,
- const expected<U, F> &rhs) {
- return (lhs.has_value() != rhs.has_value())
- ? false
- : (!lhs.has_value() ? lhs.error() == rhs.error() : *lhs == *rhs);
- }
- template <class T, class E, class U, class F>
- constexpr bool operator!=(const expected<T, E> &lhs,
- const expected<U, F> &rhs) {
- return (lhs.has_value() != rhs.has_value())
- ? true
- : (!lhs.has_value() ? lhs.error() != rhs.error() : *lhs != *rhs);
- }
- template <class E, class F>
- constexpr bool operator==(const expected<void, E> &lhs,
- const expected<void, F> &rhs) {
- return (lhs.has_value() != rhs.has_value())
- ? false
- : (!lhs.has_value() ? lhs.error() == rhs.error() : true);
- }
- template <class E, class F>
- constexpr bool operator!=(const expected<void, E> &lhs,
- const expected<void, F> &rhs) {
- return (lhs.has_value() != rhs.has_value())
- ? true
- : (!lhs.has_value() ? lhs.error() == rhs.error() : false);
- }
- template <class T, class E, class U>
- constexpr bool operator==(const expected<T, E> &x, const U &v) {
- return x.has_value() ? *x == v : false;
- }
- template <class T, class E, class U>
- constexpr bool operator==(const U &v, const expected<T, E> &x) {
- return x.has_value() ? *x == v : false;
- }
- template <class T, class E, class U>
- constexpr bool operator!=(const expected<T, E> &x, const U &v) {
- return x.has_value() ? *x != v : true;
- }
- template <class T, class E, class U>
- constexpr bool operator!=(const U &v, const expected<T, E> &x) {
- return x.has_value() ? *x != v : true;
- }
- template <class T, class E>
- constexpr bool operator==(const expected<T, E> &x, const unexpected<E> &e) {
- return x.has_value() ? false : x.error() == e.value();
- }
- template <class T, class E>
- constexpr bool operator==(const unexpected<E> &e, const expected<T, E> &x) {
- return x.has_value() ? false : x.error() == e.value();
- }
- template <class T, class E>
- constexpr bool operator!=(const expected<T, E> &x, const unexpected<E> &e) {
- return x.has_value() ? true : x.error() != e.value();
- }
- template <class T, class E>
- constexpr bool operator!=(const unexpected<E> &e, const expected<T, E> &x) {
- return x.has_value() ? true : x.error() != e.value();
- }
- template <class T, class E,
- detail::enable_if_t<(std::is_void<T>::value ||
- std::is_move_constructible<T>::value) &&
- detail::is_swappable<T>::value &&
- std::is_move_constructible<E>::value &&
- detail::is_swappable<E>::value> * = nullptr>
- void swap(expected<T, E> &lhs,
- expected<T, E> &rhs) noexcept(noexcept(lhs.swap(rhs))) {
- lhs.swap(rhs);
- }
- } // namespace tl
- #endif
|