diff --git a/external/expected.hpp b/external/expected.hpp index 92eed40b5..54960a284 100644 --- a/external/expected.hpp +++ b/external/expected.hpp @@ -13,8 +13,8 @@ #define NONSTD_EXPECTED_LITE_HPP #define expected_lite_MAJOR 0 -#define expected_lite_MINOR 6 -#define expected_lite_PATCH 3 +#define expected_lite_MINOR 8 +#define expected_lite_PATCH 0 #define expected_lite_VERSION expected_STRINGIFY(expected_lite_MAJOR) "." expected_STRINGIFY(expected_lite_MINOR) "." expected_STRINGIFY(expected_lite_PATCH) @@ -66,6 +66,37 @@ # define nsel_P0323R 7 #endif +// Monadic operations proposal revisions: +// +// P2505R0: 0 (2021-12-12) +// P2505R1: 1 (2022-02-10) +// P2505R2: 2 (2022-04-15) +// P2505R3: 3 (2022-06-05) +// P2505R4: 4 (2022-06-15) +// P2505R5: 5 (2022-09-20) * +// +// expected-lite uses 5 + +#ifndef nsel_P2505R +# define nsel_P2505R 5 +#endif + +// Lean and mean inclusion of Windows.h, if applicable; default on for MSVC: + +#if !defined(nsel_CONFIG_WIN32_LEAN_AND_MEAN) && defined(_MSC_VER) +# define nsel_CONFIG_WIN32_LEAN_AND_MEAN 1 +#else +# define nsel_CONFIG_WIN32_LEAN_AND_MEAN 0 +#endif + +// Control marking class expected with [[nodiscard]]]: + +#if !defined(nsel_CONFIG_NO_NODISCARD) +# define nsel_CONFIG_NO_NODISCARD 0 +#else +# define nsel_CONFIG_NO_NODISCARD 1 +#endif + // Control presence of C++ exception handling (try and auto discover): #ifndef nsel_CONFIG_NO_EXCEPTIONS @@ -81,7 +112,9 @@ // at default use SEH with MSVC for no C++ exceptions -#ifndef nsel_CONFIG_NO_EXCEPTIONS_SEH +#if !defined(nsel_CONFIG_NO_EXCEPTIONS_SEH) && defined(_MSC_VER) +# define nsel_CONFIG_NO_EXCEPTIONS_SEH nsel_CONFIG_NO_EXCEPTIONS +#else # define nsel_CONFIG_NO_EXCEPTIONS_SEH 0 #endif @@ -216,8 +249,37 @@ inline in_place_t in_place_index( detail::in_place_index_tag = detail::in_pla namespace nonstd { using std::expected; -// ... -} + using std::unexpected; + using std::bad_expected_access; + using std::unexpect_t; + using std::unexpect; + + //[[deprecated("replace unexpected_type with unexpected")]] + + template< typename E > + using unexpected_type = unexpected; + + // Unconditionally provide make_unexpected(): + + template< typename E > + constexpr auto make_unexpected( E && value ) -> unexpected< typename std::decay::type > + { + return unexpected< typename std::decay::type >( std::forward(value) ); + } + + template + < + typename E, typename... Args, + typename = std::enable_if< + std::is_constructible::value + > + > + constexpr auto + make_unexpected( std::in_place_t inplace, Args &&... args ) -> unexpected_type< typename std::decay::type > + { + return unexpected_type< typename std::decay::type >( inplace, std::forward(args)...); + } +} // namespace nonstd #else // nsel_USES_STD_EXPECTED @@ -233,6 +295,12 @@ namespace nonstd { // additional includes: +#if nsel_CONFIG_WIN32_LEAN_AND_MEAN +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +#endif + #if nsel_CONFIG_NO_EXCEPTIONS # if nsel_CONFIG_NO_EXCEPTIONS_SEH # include // for ExceptionCodes @@ -316,16 +384,6 @@ namespace nonstd { #define nsel_REQUIRES_A(...) \ , typename std::enable_if< (__VA_ARGS__), void*>::type = nullptr -// Presence of language and library features: - -#ifdef _HAS_CPP0X -# define nsel_HAS_CPP0X _HAS_CPP0X -#else -# define nsel_HAS_CPP0X 0 -#endif - -//#define nsel_CPP11_140 (nsel_CPP11_OR_GREATER || nsel_COMPILER_MSVC_VER >= 1900) - // Clang, GNUC, MSVC warning suppression macros: #ifdef __clang__ @@ -335,27 +393,65 @@ namespace nonstd { #endif // __clang__ #if nsel_COMPILER_MSVC_VERSION >= 140 -# pragma warning( push ) -# define nsel_DISABLE_MSVC_WARNINGS(codes) __pragma( warning(disable: codes) ) +# define nsel_DISABLE_MSVC_WARNINGS(codes) __pragma( warning(push) ) __pragma( warning(disable: codes) ) #else # define nsel_DISABLE_MSVC_WARNINGS(codes) #endif #ifdef __clang__ -# define nsel_RESTORE_WARNINGS() _Pragma("clang diagnostic pop") +# define nsel_RESTORE_WARNINGS() _Pragma("clang diagnostic pop") +# define nsel_RESTORE_MSVC_WARNINGS() #elif defined __GNUC__ -# define nsel_RESTORE_WARNINGS() _Pragma("GCC diagnostic pop") +# define nsel_RESTORE_WARNINGS() _Pragma("GCC diagnostic pop") +# define nsel_RESTORE_MSVC_WARNINGS() #elif nsel_COMPILER_MSVC_VERSION >= 140 -# define nsel_RESTORE_WARNINGS() __pragma( warning( pop ) ) +# define nsel_RESTORE_WARNINGS() __pragma( warning( pop ) ) +# define nsel_RESTORE_MSVC_WARNINGS() nsel_RESTORE_WARNINGS() #else # define nsel_RESTORE_WARNINGS() +# define nsel_RESTORE_MSVC_WARNINGS() #endif // Suppress the following MSVC (GSL) warnings: // - C26409: Avoid calling new and delete explicitly, use std::make_unique instead (r.11) nsel_DISABLE_MSVC_WARNINGS( 26409 ) -nsel_DISABLE_MSVC_WARNINGS( 4702 ) + +// Presence of language and library features: + +#ifdef _HAS_CPP0X +# define nsel_HAS_CPP0X _HAS_CPP0X +#else +# define nsel_HAS_CPP0X 0 +#endif + +// Presence of language and library features: + +#define nsel_CPP11_000 (nsel_CPP11_OR_GREATER) +#define nsel_CPP17_000 (nsel_CPP17_OR_GREATER) + +// Presence of C++11 library features: + +#define nsel_HAVE_ADDRESSOF nsel_CPP11_000 + +// Presence of C++17 language features: + +#define nsel_HAVE_DEPRECATED nsel_CPP17_000 +#define nsel_HAVE_NODISCARD nsel_CPP17_000 + +// C++ feature usage: + +#if nsel_HAVE_DEPRECATED +# define nsel_deprecated(msg) [[deprecated(msg)]] +#else +# define nsel_deprecated(msg) /*[[deprecated]]*/ +#endif + +#if nsel_HAVE_NODISCARD && !nsel_CONFIG_NO_NODISCARD +# define nsel_NODISCARD [[nodiscard]] +#else +# define nsel_NODISCARD /*[[nodiscard]]*/ +#endif // // expected: @@ -363,6 +459,25 @@ nsel_DISABLE_MSVC_WARNINGS( 4702 ) namespace nonstd { namespace expected_lite { +// library features C++11: + +namespace std11 { + +// #if 0 && nsel_HAVE_ADDRESSOF +#if nsel_HAVE_ADDRESSOF + using std::addressof; +#else + template< class T > + T * addressof( T & arg ) noexcept + { + return &arg; + } + + template< class T > + const T * addressof( const T && ) = delete; +#endif +} // namespace std11 + // type traits C++17: namespace std17 { @@ -453,6 +568,14 @@ class expected; namespace detail { +#if nsel_P2505R >= 3 +template< typename T > +struct is_expected : std::false_type {}; + +template< typename T, typename E > +struct is_expected< expected< T, E > > : std::true_type {}; +#endif // nsel_P2505R >= 3 + /// discriminated union to hold value or 'error'. template< typename T, typename E > @@ -474,29 +597,29 @@ class storage_t_noncopy_nonmove_impl void construct_value() { - new( &m_value ) value_type(); + new( std11::addressof(m_value) ) value_type(); } // void construct_value( value_type const & e ) // { - // new( &m_value ) value_type( e ); + // new( std11::addressof(m_value) ) value_type( e ); // } // void construct_value( value_type && e ) // { - // new( &m_value ) value_type( std::move( e ) ); + // new( std11::addressof(m_value) ) value_type( std::move( e ) ); // } template< class... Args > void emplace_value( Args&&... args ) { - new( &m_value ) value_type( std::forward(args)...); + new( std11::addressof(m_value) ) value_type( std::forward(args)...); } template< class U, class... Args > void emplace_value( std::initializer_list il, Args&&... args ) { - new( &m_value ) value_type( il, std::forward(args)... ); + new( std11::addressof(m_value) ) value_type( il, std::forward(args)... ); } void destruct_value() @@ -506,24 +629,24 @@ class storage_t_noncopy_nonmove_impl // void construct_error( error_type const & e ) // { - // // new( &m_error ) error_type( e ); + // // new( std11::addressof(m_error) ) error_type( e ); // } // void construct_error( error_type && e ) // { - // // new( &m_error ) error_type( std::move( e ) ); + // // new( std11::addressof(m_error) ) error_type( std::move( e ) ); // } template< class... Args > void emplace_error( Args&&... args ) { - new( &m_error ) error_type( std::forward(args)...); + new( std11::addressof(m_error) ) error_type( std::forward(args)...); } template< class U, class... Args > void emplace_error( std::initializer_list il, Args&&... args ) { - new( &m_error ) error_type( il, std::forward(args)... ); + new( std11::addressof(m_error) ) error_type( il, std::forward(args)... ); } void destruct_error() @@ -553,12 +676,12 @@ class storage_t_noncopy_nonmove_impl value_type const * value_ptr() const { - return &m_value; + return std11::addressof(m_value); } value_type * value_ptr() { - return &m_value; + return std11::addressof(m_value); } error_type const & error() const & @@ -620,29 +743,29 @@ class storage_t_impl void construct_value() { - new( &m_value ) value_type(); + new( std11::addressof(m_value) ) value_type(); } void construct_value( value_type const & e ) { - new( &m_value ) value_type( e ); + new( std11::addressof(m_value) ) value_type( e ); } void construct_value( value_type && e ) { - new( &m_value ) value_type( std::move( e ) ); + new( std11::addressof(m_value) ) value_type( std::move( e ) ); } template< class... Args > void emplace_value( Args&&... args ) { - new( &m_value ) value_type( std::forward(args)...); + new( std11::addressof(m_value) ) value_type( std::forward(args)...); } template< class U, class... Args > void emplace_value( std::initializer_list il, Args&&... args ) { - new( &m_value ) value_type( il, std::forward(args)... ); + new( std11::addressof(m_value) ) value_type( il, std::forward(args)... ); } void destruct_value() @@ -652,24 +775,24 @@ class storage_t_impl void construct_error( error_type const & e ) { - new( &m_error ) error_type( e ); + new( std11::addressof(m_error) ) error_type( e ); } void construct_error( error_type && e ) { - new( &m_error ) error_type( std::move( e ) ); + new( std11::addressof(m_error) ) error_type( std::move( e ) ); } template< class... Args > void emplace_error( Args&&... args ) { - new( &m_error ) error_type( std::forward(args)...); + new( std11::addressof(m_error) ) error_type( std::forward(args)...); } template< class U, class... Args > void emplace_error( std::initializer_list il, Args&&... args ) { - new( &m_error ) error_type( il, std::forward(args)... ); + new( std11::addressof(m_error) ) error_type( il, std::forward(args)... ); } void destruct_error() @@ -699,12 +822,12 @@ class storage_t_impl value_type const * value_ptr() const { - return &m_value; + return std11::addressof(m_value); } value_type * value_ptr() { - return &m_value; + return std11::addressof(m_value); } error_type const & error() const & @@ -750,7 +873,7 @@ class storage_t_impl /// discriminated union to hold only 'error'. template< typename E > -struct storage_t_impl +struct storage_t_impl< void, E > { template< typename, typename > friend class nonstd::expected_lite::expected; @@ -768,24 +891,24 @@ struct storage_t_impl void construct_error( error_type const & e ) { - new( &m_error ) error_type( e ); + new( std11::addressof(m_error) ) error_type( e ); } void construct_error( error_type && e ) { - new( &m_error ) error_type( std::move( e ) ); + new( std11::addressof(m_error) ) error_type( std::move( e ) ); } template< class... Args > void emplace_error( Args&&... args ) { - new( &m_error ) error_type( std::forward(args)...); + new( std11::addressof(m_error) ) error_type( std::forward(args)...); } template< class U, class... Args > void emplace_error( std::initializer_list il, Args&&... args ) { - new( &m_error ) error_type( il, std::forward(args)... ); + new( std11::addressof(m_error) ) error_type( il, std::forward(args)... ); } void destruct_error() @@ -991,6 +1114,146 @@ class storage_t : public storage_t_impl } }; +#if nsel_P2505R >= 3 +// C++11 invoke implementation +template< typename > +struct is_reference_wrapper : std::false_type {}; +template< typename T > +struct is_reference_wrapper< std::reference_wrapper< T > > : std::true_type {}; + +template< typename FnT, typename ClassT, typename ObjectT, typename... Args + nsel_REQUIRES_T( + std::is_function::value + && ( std::is_same< ClassT, typename std20::remove_cvref< ObjectT >::type >::value + || std::is_base_of< ClassT, typename std20::remove_cvref< ObjectT >::type >::value ) + ) +> +nsel_constexpr auto invoke_member_function_impl( FnT ClassT::* memfnptr, ObjectT && obj, Args && ... args ) + noexcept( noexcept( (std::forward< ObjectT >( obj ).*memfnptr)( std::forward< Args >( args )... ) ) ) + -> decltype( (std::forward< ObjectT >( obj ).*memfnptr)( std::forward< Args >( args )...) ) +{ + return (std::forward< ObjectT >( obj ).*memfnptr)( std::forward< Args >( args )... ); +} + +template< typename FnT, typename ClassT, typename ObjectT, typename... Args + nsel_REQUIRES_T( + std::is_function::value + && is_reference_wrapper< typename std20::remove_cvref< ObjectT >::type >::value + ) +> +nsel_constexpr auto invoke_member_function_impl( FnT ClassT::* memfnptr, ObjectT && obj, Args && ... args ) + noexcept( noexcept( (obj.get().*memfnptr)( std::forward< Args >( args ) ... ) ) ) + -> decltype( (obj.get().*memfnptr)( std::forward< Args >( args ) ... ) ) +{ + return (obj.get().*memfnptr)( std::forward< Args >( args ) ... ); +} + +template< typename FnT, typename ClassT, typename ObjectT, typename... Args + nsel_REQUIRES_T( + std::is_function::value + && !std::is_same< ClassT, typename std20::remove_cvref< ObjectT >::type >::value + && !std::is_base_of< ClassT, typename std20::remove_cvref< ObjectT >::type >::value + && !is_reference_wrapper< typename std20::remove_cvref< ObjectT >::type >::value + ) +> +nsel_constexpr auto invoke_member_function_impl( FnT ClassT::* memfnptr, ObjectT && obj, Args && ... args ) + noexcept( noexcept( ((*std::forward< ObjectT >( obj )).*memfnptr)( std::forward< Args >( args ) ... ) ) ) + -> decltype( ((*std::forward< ObjectT >( obj )).*memfnptr)( std::forward< Args >( args ) ... ) ) +{ + return ((*std::forward(obj)).*memfnptr)( std::forward< Args >( args ) ... ); +} + +template< typename MemberT, typename ClassT, typename ObjectT + nsel_REQUIRES_T( + std::is_same< ClassT, typename std20::remove_cvref< ObjectT >::type >::value + || std::is_base_of< ClassT, typename std20::remove_cvref< ObjectT >::type >::value + ) +> +nsel_constexpr auto invoke_member_object_impl( MemberT ClassT::* memobjptr, ObjectT && obj ) + noexcept( noexcept( std::forward< ObjectT >( obj ).*memobjptr ) ) + -> decltype( std::forward< ObjectT >( obj ).*memobjptr ) +{ + return std::forward< ObjectT >( obj ).*memobjptr; +} + +template< typename MemberT, typename ClassT, typename ObjectT + nsel_REQUIRES_T( + is_reference_wrapper< typename std20::remove_cvref< ObjectT >::type >::value + ) +> +nsel_constexpr auto invoke_member_object_impl( MemberT ClassT::* memobjptr, ObjectT && obj ) + noexcept( noexcept( obj.get().*memobjptr ) ) + -> decltype( obj.get().*memobjptr ) +{ + return obj.get().*memobjptr; +} + +template< typename MemberT, typename ClassT, typename ObjectT + nsel_REQUIRES_T( + !std::is_same< ClassT, typename std20::remove_cvref< ObjectT >::type >::value + && !std::is_base_of< ClassT, typename std20::remove_cvref< ObjectT >::type >::value + && !is_reference_wrapper< typename std20::remove_cvref< ObjectT >::type >::value + ) +> +nsel_constexpr auto invoke_member_object_impl( MemberT ClassT::* memobjptr, ObjectT && obj ) + noexcept( noexcept( (*std::forward< ObjectT >( obj )).*memobjptr ) ) + -> decltype( (*std::forward< ObjectT >( obj )).*memobjptr ) +{ + return (*std::forward< ObjectT >( obj )).*memobjptr; +} + +template< typename F, typename... Args + nsel_REQUIRES_T( + std::is_member_function_pointer< typename std20::remove_cvref< F >::type >::value + ) +> +nsel_constexpr auto invoke( F && f, Args && ... args ) + noexcept( noexcept( invoke_member_function_impl( std::forward< F >( f ), std::forward< Args >( args ) ... ) ) ) + -> decltype( invoke_member_function_impl( std::forward< F >( f ), std::forward< Args >( args ) ... ) ) +{ + return invoke_member_function_impl( std::forward< F >( f ), std::forward< Args >( args ) ... ); +} + +template< typename F, typename... Args + nsel_REQUIRES_T( + std::is_member_object_pointer< typename std20::remove_cvref< F >::type >::value + ) +> +nsel_constexpr auto invoke( F && f, Args && ... args ) + noexcept( noexcept( invoke_member_object_impl( std::forward< F >( f ), std::forward< Args >( args ) ... ) ) ) + -> decltype( invoke_member_object_impl( std::forward< F >( f ), std::forward< Args >( args ) ... ) ) +{ + return invoke_member_object_impl( std::forward< F >( f ), std::forward< Args >( args ) ... ); +} + +template< typename F, typename... Args + nsel_REQUIRES_T( + !std::is_member_function_pointer< typename std20::remove_cvref< F >::type >::value + && !std::is_member_object_pointer< typename std20::remove_cvref< F >::type >::value + ) +> +nsel_constexpr auto invoke( F && f, Args && ... args ) + noexcept( noexcept( std::forward< F >( f )( std::forward< Args >( args ) ... ) ) ) + -> decltype( std::forward< F >( f )( std::forward< Args >( args ) ... ) ) +{ + return std::forward< F >( f )( std::forward< Args >( args ) ... ); +} + +template< typename F, typename ... Args > +using invoke_result_nocvref_t = typename std20::remove_cvref< decltype( invoke( std::declval< F >(), std::declval< Args >()... ) ) >::type; + +#if nsel_P2505R >= 5 +template< typename F, typename ... Args > +using transform_invoke_result_t = typename std::remove_cv< decltype( invoke( std::declval< F >(), std::declval< Args >()... ) ) >::type; +#else +template< typename F, typename ... Args > +using transform_invoke_result_t = invoke_result_nocvref_t +#endif // nsel_P2505R >= 5 + +template< typename T > +struct valid_expected_value_type : std::integral_constant< bool, std::is_destructible< T >::value && !std::is_reference< T >::value && !std::is_array< T >::value > {}; + +#endif // nsel_P2505R >= 3 } // namespace detail /// x.x.5 Unexpected object type; unexpected_type; C++17 and later can also use aliased type unexpected. @@ -1057,7 +1320,7 @@ class unexpected_type ) > constexpr explicit unexpected_type( unexpected_type const & error ) - : m_error( E{ error.value() } ) + : m_error( E{ error.error() } ) {} template< typename E2 @@ -1075,7 +1338,7 @@ class unexpected_type ) > constexpr /*non-explicit*/ unexpected_type( unexpected_type const & error ) - : m_error( error.value() ) + : m_error( error.error() ) {} template< typename E2 @@ -1093,7 +1356,7 @@ class unexpected_type ) > constexpr explicit unexpected_type( unexpected_type && error ) - : m_error( E{ std::move( error.value() ) } ) + : m_error( E{ std::move( error.error() ) } ) {} template< typename E2 @@ -1111,7 +1374,7 @@ class unexpected_type ) > constexpr /*non-explicit*/ unexpected_type( unexpected_type && error ) - : m_error( std::move( error.value() ) ) + : m_error( std::move( error.error() ) ) {} // x.x.5.2.2 Assignment @@ -1122,24 +1385,54 @@ class unexpected_type template< typename E2 = E > nsel_constexpr14 unexpected_type & operator=( unexpected_type const & other ) { - unexpected_type{ other.value() }.swap( *this ); + unexpected_type{ other.error() }.swap( *this ); return *this; } template< typename E2 = E > nsel_constexpr14 unexpected_type & operator=( unexpected_type && other ) { - unexpected_type{ std::move( other.value() ) }.swap( *this ); + unexpected_type{ std::move( other.error() ) }.swap( *this ); return *this; } // x.x.5.2.3 Observers + nsel_constexpr14 E & error() & noexcept + { + return m_error; + } + + constexpr E const & error() const & noexcept + { + return m_error; + } + +#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 + + nsel_constexpr14 E && error() && noexcept + { + return std::move( m_error ); + } + + constexpr E const && error() const && noexcept + { + return std::move( m_error ); + } + +#endif + + // x.x.5.2.3 Observers - deprecated + + nsel_deprecated("replace value() with error()") + nsel_constexpr14 E & value() & noexcept { return m_error; } + nsel_deprecated("replace value() with error()") + constexpr E const & value() const & noexcept { return m_error; @@ -1147,11 +1440,15 @@ class unexpected_type #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 + nsel_deprecated("replace value() with error()") + nsel_constexpr14 E && value() && noexcept { return std::move( m_error ); } + nsel_deprecated("replace value() with error()") + constexpr E const && value() const && noexcept { return std::move( m_error ); @@ -1240,7 +1537,7 @@ class unexpected_type< std::exception_ptr > template< typename E1, typename E2 > constexpr bool operator==( unexpected_type const & x, unexpected_type const & y ) { - return x.value() == y.value(); + return x.error() == y.error(); } template< typename E1, typename E2 > @@ -1254,7 +1551,7 @@ constexpr bool operator!=( unexpected_type const & x, unexpected_type co template< typename E > constexpr bool operator<( unexpected_type const & x, unexpected_type const & y ) { - return x.value() < y.value(); + return x.error() < y.error(); } template< typename E > @@ -1319,10 +1616,10 @@ inline constexpr bool operator>=( unexpected_type const & x, #if nsel_P0323R <= 3 -template< typename E> +template< typename E > struct is_unexpected : std::false_type {}; -template< typename E> +template< typename E > struct is_unexpected< unexpected_type > : std::true_type {}; #endif // nsel_P0323R @@ -1331,13 +1628,26 @@ struct is_unexpected< unexpected_type > : std::true_type {}; // keep make_unexpected() removed in p0323r2 for pre-C++17: -template< typename E> +template< typename E > nsel_constexpr14 auto make_unexpected( E && value ) -> unexpected_type< typename std::decay::type > { return unexpected_type< typename std::decay::type >( std::forward(value) ); } +template +< + typename E, typename... Args, + typename = std::enable_if< + std::is_constructible::value + > +> +nsel_constexpr14 auto +make_unexpected( nonstd_lite_in_place_t(E), Args &&... args ) -> unexpected_type< typename std::decay::type > +{ + return std::move( unexpected_type< typename std::decay::type >( nonstd_lite_in_place(E), std::forward(args)...) ); +} + #if nsel_P0323R <= 3 /*nsel_constexpr14*/ auto inline @@ -1499,6 +1809,24 @@ struct error_traits< std::error_code > #endif // nsel_CONFIG_NO_EXCEPTIONS +#if nsel_P2505R >= 3 +namespace detail { + +// from https://en.cppreference.com/w/cpp/utility/expected/unexpected: +// "the type of the unexpected value. The type must not be an array type, a non-object type, a specialization of std::unexpected, or a cv-qualified type." +template< typename T > +struct valid_unexpected_type : std::integral_constant< bool, + std::is_same< T, typename std20::remove_cvref< T >::type >::value + && std::is_object< T >::value + && !std::is_array< T >::value +> {}; + +template< typename T > +struct valid_unexpected_type< unexpected_type< T > > : std::false_type {}; + +} // namespace detail +#endif // nsel_P2505R >= 3 + } // namespace expected_lite // provide nonstd::unexpected_type: @@ -1511,10 +1839,10 @@ namespace expected_lite { #if nsel_P0323R <= 2 template< typename T, typename E = std::exception_ptr > -class expected +class nsel_NODISCARD expected #else template< typename T, typename E > -class expected +class nsel_NODISCARD expected #endif // nsel_P0323R { private: @@ -1693,7 +2021,7 @@ class expected nsel_constexpr14 explicit expected( nonstd::unexpected_type const & error ) : contained( false ) { - contained.construct_error( E{ error.value() } ); + contained.construct_error( E{ error.error() } ); } template< typename G = E @@ -1705,7 +2033,7 @@ class expected nsel_constexpr14 /*non-explicit*/ expected( nonstd::unexpected_type const & error ) : contained( false ) { - contained.construct_error( error.value() ); + contained.construct_error( error.error() ); } template< typename G = E @@ -1717,7 +2045,7 @@ class expected nsel_constexpr14 explicit expected( nonstd::unexpected_type && error ) : contained( false ) { - contained.construct_error( E{ std::move( error.value() ) } ); + contained.construct_error( E{ std::move( error.error() ) } ); } template< typename G = E @@ -1729,7 +2057,7 @@ class expected nsel_constexpr14 /*non-explicit*/ expected( nonstd::unexpected_type && error ) : contained( false ) { - contained.construct_error( std::move( error.value() ) ); + contained.construct_error( std::move( error.error() ) ); } // in-place construction, value @@ -1834,7 +2162,7 @@ class expected > expected & operator=( nonstd::unexpected_type const & error ) { - expected( unexpect, error.value() ).swap( *this ); + expected( unexpect, error.error() ).swap( *this ); return *this; } @@ -1847,7 +2175,7 @@ class expected > expected & operator=( nonstd::unexpected_type && error ) { - expected( unexpect, std::move( error.value() ) ).swap( *this ); + expected( unexpect, std::move( error.error() ) ).swap( *this ); return *this; } @@ -1950,6 +2278,8 @@ class expected return contained.has_value(); } + nsel_DISABLE_MSVC_WARNINGS( 4702 ) // warning C4702: unreachable code, see issue 65. + constexpr value_type const & value() const & { return has_value() @@ -1963,6 +2293,7 @@ class expected ? ( contained.value() ) : ( error_traits::rethrow( contained.error() ), contained.value() ); } + nsel_RESTORE_MSVC_WARNINGS() #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 @@ -2014,7 +2345,7 @@ class expected template< typename Ex > bool has_exception() const { - using ContainedEx = typename std::remove_reference< decltype( get_unexpected().value() ) >::type; + using ContainedEx = typename std::remove_reference< decltype( get_unexpected().error() ) >::type; return ! has_value() && std::is_base_of< Ex, ContainedEx>::value; } @@ -2044,6 +2375,316 @@ class expected : static_cast( std::forward( v ) ); } +#if nsel_P2505R >= 4 + template< typename G = E + nsel_REQUIRES_T( + std::is_copy_constructible< E >::value + && std::is_convertible< G, E >::value + ) + > + nsel_constexpr error_type error_or( G && e ) const & + { + return has_value() + ? static_cast< E >( std::forward< G >( e ) ) + : contained.error(); + } + + template< typename G = E + nsel_REQUIRES_T( + std::is_move_constructible< E >::value + && std::is_convertible< G, E >::value + ) + > + nsel_constexpr14 error_type error_or( G && e ) && + { + return has_value() + ? static_cast< E >( std::forward< G >( e ) ) + : std::move( contained.error() ); + } +#endif // nsel_P2505R >= 4 + +#if nsel_P2505R >= 3 + // Monadic operations (P2505) + template< typename F + nsel_REQUIRES_T( + detail::is_expected < detail::invoke_result_nocvref_t< F, value_type & > > ::value + && std::is_same< typename detail::invoke_result_nocvref_t< F, value_type & >::error_type, error_type >::value + && std::is_constructible< error_type, error_type & >::value + ) + > + nsel_constexpr14 detail::invoke_result_nocvref_t< F, value_type & > and_then( F && f ) & + { + return has_value() + ? detail::invoke_result_nocvref_t< F, value_type & >( detail::invoke( std::forward< F >( f ), value() ) ) + : detail::invoke_result_nocvref_t< F, value_type & >( unexpect, error() ); + } + + template >::value + && std::is_same< typename detail::invoke_result_nocvref_t< F, const value_type & >::error_type, error_type >::value + && std::is_constructible< error_type, const error_type & >::value + ) + > + nsel_constexpr detail::invoke_result_nocvref_t< F, const value_type & > and_then( F && f ) const & + { + return has_value() + ? detail::invoke_result_nocvref_t< F, const value_type & >( detail::invoke( std::forward< F >( f ), value() ) ) + : detail::invoke_result_nocvref_t< F, const value_type & >( unexpect, error() ); + } + +#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 + template >::value + && std::is_same< typename detail::invoke_result_nocvref_t< F, value_type && >::error_type, error_type >::value + && std::is_constructible< error_type, error_type && >::value + ) + > + nsel_constexpr14 detail::invoke_result_nocvref_t< F, value_type && > and_then( F && f ) && + { + return has_value() + ? detail::invoke_result_nocvref_t< F, value_type && >( detail::invoke( std::forward< F >( f ), std::move( value() ) ) ) + : detail::invoke_result_nocvref_t< F, value_type && >( unexpect, std::move( error() ) ); + } + + template >::value + && std::is_same< typename detail::invoke_result_nocvref_t< F, const value_type & >::error_type, error_type >::value + && std::is_constructible< error_type, const error_type && >::value + ) + > + nsel_constexpr detail::invoke_result_nocvref_t< F, const value_type && > and_then( F && f ) const && + { + return has_value() + ? detail::invoke_result_nocvref_t< F, const value_type && >( detail::invoke( std::forward< F >( f ), std::move( value() ) ) ) + : detail::invoke_result_nocvref_t< F, const value_type && >( unexpect, std::move( error() ) ); + } +#endif + + template >::value + && std::is_same< typename detail::invoke_result_nocvref_t< F, error_type & >::value_type, value_type >::value + && std::is_constructible< value_type, value_type & >::value + ) + > + nsel_constexpr14 detail::invoke_result_nocvref_t< F, error_type & > or_else( F && f ) & + { + return has_value() + ? detail::invoke_result_nocvref_t< F, error_type & >( value() ) + : detail::invoke_result_nocvref_t< F, error_type & >( detail::invoke( std::forward< F >( f ), error() ) ); + } + + template >::value + && std::is_same< typename detail::invoke_result_nocvref_t< F, const error_type & >::value_type, value_type >::value + && std::is_constructible< value_type, const value_type & >::value + ) + > + nsel_constexpr detail::invoke_result_nocvref_t< F, const error_type & > or_else( F && f ) const & + { + return has_value() + ? detail::invoke_result_nocvref_t< F, const error_type & >( value() ) + : detail::invoke_result_nocvref_t< F, const error_type & >( detail::invoke( std::forward< F >( f ), error() ) ); + } + +#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 + template >::value + && std::is_same< typename detail::invoke_result_nocvref_t< F, error_type && >::value_type, value_type >::value + && std::is_constructible< value_type, value_type && >::value + ) + > + nsel_constexpr14 detail::invoke_result_nocvref_t< F, error_type && > or_else( F && f ) && + { + return has_value() + ? detail::invoke_result_nocvref_t< F, error_type && >( std::move( value() ) ) + : detail::invoke_result_nocvref_t< F, error_type && >( detail::invoke( std::forward< F >( f ), std::move( error() ) ) ); + } + + template >::value + && std::is_same< typename detail::invoke_result_nocvref_t< F, const error_type && >::value_type, value_type >::value + && std::is_constructible< value_type, const value_type && >::value + ) + > + nsel_constexpr detail::invoke_result_nocvref_t< F, const error_type && > or_else( F && f ) const && + { + return has_value() + ? detail::invoke_result_nocvref_t< F, const error_type && >( std::move( value() ) ) + : detail::invoke_result_nocvref_t< F, const error_type && >( detail::invoke( std::forward< F >( f ), std::move( error() ) ) ); + } +#endif + + template::value + && !std::is_void< detail::transform_invoke_result_t< F, value_type & > >::value + && detail::valid_expected_value_type< detail::transform_invoke_result_t< F, value_type & > >::value + ) + > + nsel_constexpr14 expected< detail::transform_invoke_result_t< F, value_type & >, error_type > transform( F && f ) & + { + return has_value() + ? expected< detail::transform_invoke_result_t< F, value_type & >, error_type >( detail::invoke( std::forward< F >( f ), **this ) ) + : make_unexpected( error() ); + } + + template::value + && std::is_void< detail::transform_invoke_result_t< F, value_type & > >::value + ) + > + nsel_constexpr14 expected< void, error_type > transform( F && f ) & + { + return has_value() + ? ( detail::invoke( std::forward< F >( f ), **this ), expected< void, error_type >() ) + : make_unexpected( error() ); + } + + template::value + && !std::is_void< detail::transform_invoke_result_t< F, const value_type & > >::value + && detail::valid_expected_value_type< detail::transform_invoke_result_t< F, const value_type & > >::value + ) + > + nsel_constexpr expected< detail::transform_invoke_result_t< F, const value_type & >, error_type > transform( F && f ) const & + { + return has_value() + ? expected< detail::transform_invoke_result_t< F, const value_type & >, error_type >( detail::invoke( std::forward< F >( f ), **this ) ) + : make_unexpected( error() ); + } + + template::value + && std::is_void< detail::transform_invoke_result_t< F, const value_type & > >::value + ) + > + nsel_constexpr expected< void, error_type > transform( F && f ) const & + { + return has_value() + ? ( detail::invoke( std::forward< F >( f ), **this ), expected< void, error_type >() ) + : make_unexpected( error() ); + } + +#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 + template::value + && !std::is_void< detail::transform_invoke_result_t< F, value_type && > >::value + && detail::valid_expected_value_type< detail::transform_invoke_result_t< F, value_type && > >::value + ) + > + nsel_constexpr14 expected< detail::transform_invoke_result_t< F, value_type && >, error_type > transform( F && f ) && + { + return has_value() + ? expected< detail::transform_invoke_result_t< F, value_type && >, error_type >( detail::invoke( std::forward< F >( f ), std::move( **this ) ) ) + : make_unexpected( std::move( error() ) ); + } + + template::value + && std::is_void< detail::transform_invoke_result_t< F, value_type && > >::value + ) + > + nsel_constexpr14 expected< void, error_type > transform( F && f ) && + { + return has_value() + ? ( detail::invoke( std::forward< F >( f ), **this ), expected< void, error_type >() ) + : make_unexpected( std::move( error() ) ); + } + + template::value + && !std::is_void< detail::transform_invoke_result_t< F, const value_type && > >::value + && detail::valid_expected_value_type< detail::transform_invoke_result_t< F, const value_type && > >::value + ) + > + nsel_constexpr expected< detail::transform_invoke_result_t< F, const value_type && >, error_type > transform( F && f ) const && + { + return has_value() + ? expected< detail::transform_invoke_result_t< F, const value_type && >, error_type >( detail::invoke( std::forward< F >( f ), std::move( **this ) ) ) + : make_unexpected( std::move( error() ) ); + } + + template::value + && std::is_void< detail::transform_invoke_result_t< F, const value_type && > >::value + ) + > + nsel_constexpr expected< void, error_type > transform( F && f ) const && + { + return has_value() + ? ( detail::invoke( std::forward< F >( f ), **this ), expected< void, error_type >() ) + : make_unexpected( std::move( error() ) ); + } +#endif + + template >::value + && std::is_constructible< value_type, value_type & >::value + ) + > + nsel_constexpr14 expected< value_type, detail::transform_invoke_result_t< F, error_type & > > transform_error( F && f ) & + { + return has_value() + ? expected< value_type, detail::transform_invoke_result_t< F, error_type & > >( in_place, **this ) + : make_unexpected( detail::invoke( std::forward< F >( f ), error() ) ); + } + + template >::value + && std::is_constructible< value_type, const value_type & >::value + ) + > + nsel_constexpr expected< value_type, detail::transform_invoke_result_t< F, const error_type & > > transform_error( F && f ) const & + { + return has_value() + ? expected< value_type, detail::transform_invoke_result_t< F, const error_type & > >( in_place, **this ) + : make_unexpected( detail::invoke( std::forward< F >( f ), error() ) ); + } + +#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 + template >::value + && std::is_constructible< value_type, value_type && >::value + ) + > + nsel_constexpr14 expected< value_type, detail::transform_invoke_result_t< F, error_type && > > transform_error( F && f ) && + { + return has_value() + ? expected< value_type, detail::transform_invoke_result_t< F, error_type && > >( in_place, std::move( **this ) ) + : make_unexpected( detail::invoke( std::forward< F >( f ), std::move( error() ) ) ); + } + + template >::value + && std::is_constructible< value_type, const value_type && >::value + ) + > + nsel_constexpr expected< value_type, detail::transform_invoke_result_t< F, const error_type && > > transform_error( F && f ) const && + { + return has_value() + ? expected< value_type, detail::transform_invoke_result_t< F, const error_type && > >( in_place, std::move( **this ) ) + : make_unexpected( detail::invoke( std::forward< F >( f ), std::move( error() ) ) ); + } +#endif +#endif // nsel_P2505R >= 3 // unwrap() // template @@ -2089,7 +2730,7 @@ class expected /// class expected, void specialization template< typename E > -class expected +class expected< void, E > { private: template< typename, typename > friend class expected; @@ -2120,7 +2761,7 @@ class expected nsel_constexpr14 explicit expected( nonstd::unexpected_type const & error ) : contained( false ) { - contained.construct_error( E{ error.value() } ); + contained.construct_error( E{ error.error() } ); } template< typename G = E @@ -2131,7 +2772,7 @@ class expected nsel_constexpr14 /*non-explicit*/ expected( nonstd::unexpected_type const & error ) : contained( false ) { - contained.construct_error( error.value() ); + contained.construct_error( error.error() ); } template< typename G = E @@ -2142,7 +2783,7 @@ class expected nsel_constexpr14 explicit expected( nonstd::unexpected_type && error ) : contained( false ) { - contained.construct_error( E{ std::move( error.value() ) } ); + contained.construct_error( E{ std::move( error.error() ) } ); } template< typename G = E @@ -2153,7 +2794,7 @@ class expected nsel_constexpr14 /*non-explicit*/ expected( nonstd::unexpected_type && error ) : contained( false ) { - contained.construct_error( std::move( error.value() ) ); + contained.construct_error( std::move( error.error() ) ); } template< typename... Args @@ -2286,10 +2927,309 @@ class expected template< typename Ex > bool has_exception() const { - using ContainedEx = typename std::remove_reference< decltype( get_unexpected().value() ) >::type; + using ContainedEx = typename std::remove_reference< decltype( get_unexpected().error() ) >::type; return ! has_value() && std::is_base_of< Ex, ContainedEx>::value; } +#if nsel_P2505R >= 4 + template< typename G = E + nsel_REQUIRES_T( + std::is_copy_constructible< E >::value + && std::is_convertible< G, E >::value + ) + > + nsel_constexpr error_type error_or( G && e ) const & + { + return has_value() + ? static_cast< E >( std::forward< G >( e ) ) + : contained.error(); + } + + template< typename G = E + nsel_REQUIRES_T( + std::is_move_constructible< E >::value + && std::is_convertible< G, E >::value + ) + > + nsel_constexpr14 error_type error_or( G && e ) && + { + return has_value() + ? static_cast< E >( std::forward< G >( e ) ) + : std::move( contained.error() ); + } +#endif // nsel_P2505R >= 4 + +#if nsel_P2505R >= 3 + // Monadic operations (P2505) + template >::value + && std::is_same< typename detail::invoke_result_nocvref_t< F >::error_type, error_type >::value + && std::is_constructible< error_type, error_type & >::value + ) + > + nsel_constexpr14 detail::invoke_result_nocvref_t< F > and_then( F && f ) & + { + return has_value() + ? detail::invoke_result_nocvref_t< F >( detail::invoke( std::forward< F >( f ) ) ) + : detail::invoke_result_nocvref_t< F >( unexpect, error() ); + } + + template >::value + && std::is_same< typename detail::invoke_result_nocvref_t< F >::error_type, error_type >::value + && std::is_constructible< error_type, const error_type & >::value + ) + > + nsel_constexpr detail::invoke_result_nocvref_t< F > and_then( F && f ) const & + { + return has_value() + ? detail::invoke_result_nocvref_t< F >( detail::invoke( std::forward< F >( f ) ) ) + : detail::invoke_result_nocvref_t< F >( unexpect, error() ); + } + +#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 + template >::value + && std::is_same< typename detail::invoke_result_nocvref_t< F >::error_type, error_type >::value + && std::is_constructible< error_type, error_type && >::value + ) + > + nsel_constexpr14 detail::invoke_result_nocvref_t< F > and_then( F && f ) && + { + return has_value() + ? detail::invoke_result_nocvref_t< F >( detail::invoke( std::forward< F >( f ) ) ) + : detail::invoke_result_nocvref_t< F >( unexpect, std::move( error() ) ); + } + + template >::value + && std::is_same< typename detail::invoke_result_nocvref_t< F >::error_type, error_type >::value + && std::is_constructible< error_type, const error_type && >::value + ) + > + nsel_constexpr detail::invoke_result_nocvref_t< F > and_then( F && f ) const && + { + return has_value() + ? detail::invoke_result_nocvref_t< F >( detail::invoke( std::forward< F >( f ) ) ) + : detail::invoke_result_nocvref_t< F >( unexpect, std::move( error() ) ); + } +#endif + + template >::value + && std::is_void< typename detail::invoke_result_nocvref_t< F, error_type & >::value_type >::value + ) + > + nsel_constexpr14 detail::invoke_result_nocvref_t< F, error_type & > or_else( F && f ) & + { + return has_value() + ? detail::invoke_result_nocvref_t< F, error_type & >() + : detail::invoke_result_nocvref_t< F, error_type & >( detail::invoke( std::forward< F >( f ), error() ) ); + } + + template >::value + && std::is_void< typename detail::invoke_result_nocvref_t< F, const error_type & >::value_type >::value + ) + > + nsel_constexpr detail::invoke_result_nocvref_t< F, const error_type & > or_else( F && f ) const & + { + return has_value() + ? detail::invoke_result_nocvref_t< F, const error_type & >() + : detail::invoke_result_nocvref_t< F, const error_type & >( detail::invoke( std::forward< F >( f ), error() ) ); + } + +#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 + template >::value + && std::is_void< typename detail::invoke_result_nocvref_t< F, error_type && >::value_type >::value + ) + > + nsel_constexpr14 detail::invoke_result_nocvref_t< F, error_type && > or_else( F && f ) && + { + return has_value() + ? detail::invoke_result_nocvref_t< F, error_type && >() + : detail::invoke_result_nocvref_t< F, error_type && >( detail::invoke( std::forward< F >( f ), std::move( error() ) ) ); + } + + template >::value + && std::is_void< typename detail::invoke_result_nocvref_t< F, const error_type && >::value_type >::value + ) + > + nsel_constexpr detail::invoke_result_nocvref_t< F, const error_type && > or_else( F && f ) const && + { + return has_value() + ? detail::invoke_result_nocvref_t< F, const error_type && >() + : detail::invoke_result_nocvref_t< F, const error_type && >( detail::invoke( std::forward< F >( f ), std::move( error() ) ) ); + } +#endif + + template::value + && !std::is_void< detail::transform_invoke_result_t< F > >::value + ) + > + nsel_constexpr14 expected< detail::transform_invoke_result_t< F >, error_type > transform( F && f ) & + { + return has_value() + ? expected< detail::transform_invoke_result_t< F >, error_type >( detail::invoke( std::forward< F >( f ) ) ) + : make_unexpected( error() ); + } + + template::value + && std::is_void< detail::transform_invoke_result_t< F > >::value + ) + > + nsel_constexpr14 expected< void, error_type > transform( F && f ) & + { + return has_value() + ? ( detail::invoke( std::forward< F >( f ) ), expected< void, error_type >() ) + : make_unexpected( error() ); + } + + template::value + && !std::is_void< detail::transform_invoke_result_t< F > >::value + ) + > + nsel_constexpr expected< detail::transform_invoke_result_t< F >, error_type > transform( F && f ) const & + { + return has_value() + ? expected< detail::transform_invoke_result_t< F >, error_type >( detail::invoke( std::forward< F >( f ) ) ) + : make_unexpected( error() ); + } + + template::value + && std::is_void< detail::transform_invoke_result_t< F > >::value + ) + > + nsel_constexpr expected< void, error_type > transform( F && f ) const & + { + return has_value() + ? ( detail::invoke( std::forward< F >( f ) ), expected< void, error_type >() ) + : make_unexpected( error() ); + } + +#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 + template::value + && !std::is_void< detail::transform_invoke_result_t< F > >::value + ) + > + nsel_constexpr14 expected< detail::transform_invoke_result_t< F >, error_type > transform( F && f ) && + { + return has_value() + ? expected< detail::transform_invoke_result_t< F >, error_type >( detail::invoke( std::forward< F >( f ) ) ) + : make_unexpected( error() ); + } + + template::value + && std::is_void< detail::transform_invoke_result_t< F > >::value + ) + > + nsel_constexpr14 expected< void, error_type > transform( F && f ) && + { + return has_value() + ? ( detail::invoke( std::forward< F >( f ) ), expected< void, error_type >() ) + : make_unexpected( error() ); + } + + template::value + && !std::is_void< detail::transform_invoke_result_t< F > >::value + ) + > + nsel_constexpr expected< detail::transform_invoke_result_t< F >, error_type > transform( F && f ) const && + { + return has_value() + ? expected< detail::transform_invoke_result_t< F >, error_type >( detail::invoke( std::forward< F >( f ) ) ) + : make_unexpected( error() ); + } + + template::value + && std::is_void< detail::transform_invoke_result_t< F > >::value + ) + > + nsel_constexpr expected< void, error_type > transform( F && f ) const && + { + return has_value() + ? ( detail::invoke( std::forward< F >( f ) ), expected< void, error_type >() ) + : make_unexpected( error() ); + } +#endif + + template >::value + ) + > + nsel_constexpr14 expected< void, detail::transform_invoke_result_t< F, error_type & > > transform_error( F && f ) & + { + return has_value() + ? expected< void, detail::transform_invoke_result_t< F, error_type & > >() + : make_unexpected( detail::invoke( std::forward< F >( f ), error() ) ); + } + + template >::value + ) + > + nsel_constexpr expected< void, detail::transform_invoke_result_t< F, const error_type & > > transform_error( F && f ) const & + { + return has_value() + ? expected< void, detail::transform_invoke_result_t< F, const error_type & > >() + : make_unexpected( detail::invoke( std::forward< F >( f ), error() ) ); + } + +#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490 + template >::value + ) + > + nsel_constexpr14 expected< void, detail::transform_invoke_result_t< F, error_type && > > transform_error( F && f ) && + { + return has_value() + ? expected< void, detail::transform_invoke_result_t< F, error_type && > >() + : make_unexpected( detail::invoke( std::forward< F >( f ), std::move( error() ) ) ); + } + + template >::value + ) + > + nsel_constexpr expected< void, detail::transform_invoke_result_t< F, const error_type && > > transform_error( F && f ) const && + { + return has_value() + ? expected< void, detail::transform_invoke_result_t< F, const error_type && > >() + : make_unexpected( detail::invoke( std::forward< F >( f ), std::move( error() ) ) ); + } +#endif +#endif // nsel_P2505R >= 3 + // template constexpr 'see below' unwrap() const&; // // template 'see below' unwrap() &&;