1 // This version targets C++11 and later.
3 // Copyright (C) 2016-2020 Martin Moene.
5 // Distributed under the Boost Software License, Version 1.0.
6 // (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8 // expected lite is based on:
9 // A proposal to add a utility class to represent expected monad
10 // by Vicente J. Botet Escriba and Pierre Talbot. http:://wg21.link/p0323
12 #ifndef NONSTD_EXPECTED_LITE_HPP
13 #define NONSTD_EXPECTED_LITE_HPP
15 #define expected_lite_MAJOR 0
16 #define expected_lite_MINOR 6
17 #define expected_lite_PATCH 3
19 #define expected_lite_VERSION expected_STRINGIFY(expected_lite_MAJOR) "." expected_STRINGIFY(expected_lite_MINOR) "." expected_STRINGIFY(expected_lite_PATCH)
21 #define expected_STRINGIFY( x ) expected_STRINGIFY_( x )
22 #define expected_STRINGIFY_( x ) #x
24 // expected-lite configuration:
26 #define nsel_EXPECTED_DEFAULT 0
27 #define nsel_EXPECTED_NONSTD 1
28 #define nsel_EXPECTED_STD 2
30 // tweak header support:
33 # if __has_include(<nonstd/expected.tweak.hpp>)
34 # include <nonstd/expected.tweak.hpp>
36 #define expected_HAVE_TWEAK_HEADER 1
38 #define expected_HAVE_TWEAK_HEADER 0
39 //# pragma message("expected.hpp: Note: Tweak header not supported.")
42 // expected selection and configuration:
44 #if !defined( nsel_CONFIG_SELECT_EXPECTED )
45 # define nsel_CONFIG_SELECT_EXPECTED ( nsel_HAVE_STD_EXPECTED ? nsel_EXPECTED_STD : nsel_EXPECTED_NONSTD )
48 // Proposal revisions:
51 // N4015 : -2 (2014-05-26)
52 // N4109 : -1 (2014-06-29)
53 // P0323R0: 0 (2016-05-28)
54 // P0323R1: 1 (2016-10-12)
56 // P0323R2: 2 (2017-06-15)
57 // P0323R3: 3 (2017-10-15)
58 // P0323R4: 4 (2017-11-26)
59 // P0323R5: 5 (2018-02-08)
60 // P0323R6: 6 (2018-04-02)
61 // P0323R7: 7 (2018-06-22) *
63 // expected-lite uses 2 and higher
66 # define nsel_P0323R 7
69 // Control presence of C++ exception handling (try and auto discover):
71 #ifndef nsel_CONFIG_NO_EXCEPTIONS
72 # if defined(_MSC_VER)
73 # include <cstddef> // for _HAS_EXCEPTIONS
75 # if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || (_HAS_EXCEPTIONS)
76 # define nsel_CONFIG_NO_EXCEPTIONS 0
78 # define nsel_CONFIG_NO_EXCEPTIONS 1
82 // at default use SEH with MSVC for no C++ exceptions
84 #ifndef nsel_CONFIG_NO_EXCEPTIONS_SEH
85 # define nsel_CONFIG_NO_EXCEPTIONS_SEH ( nsel_CONFIG_NO_EXCEPTIONS && _MSC_VER )
88 // C++ language version detection (C++23 is speculative):
89 // Note: VC14.0/1900 (VS2015) lacks too much from C++14.
91 #ifndef nsel_CPLUSPLUS
92 # if defined(_MSVC_LANG ) && !defined(__clang__)
93 # define nsel_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG )
95 # define nsel_CPLUSPLUS __cplusplus
99 #define nsel_CPP98_OR_GREATER ( nsel_CPLUSPLUS >= 199711L )
100 #define nsel_CPP11_OR_GREATER ( nsel_CPLUSPLUS >= 201103L )
101 #define nsel_CPP14_OR_GREATER ( nsel_CPLUSPLUS >= 201402L )
102 #define nsel_CPP17_OR_GREATER ( nsel_CPLUSPLUS >= 201703L )
103 #define nsel_CPP20_OR_GREATER ( nsel_CPLUSPLUS >= 202002L )
104 #define nsel_CPP23_OR_GREATER ( nsel_CPLUSPLUS >= 202300L )
106 // Use C++23 std::expected if available and requested:
108 #if nsel_CPP23_OR_GREATER && defined(__has_include )
109 # if __has_include( <expected> )
110 # define nsel_HAVE_STD_EXPECTED 1
112 # define nsel_HAVE_STD_EXPECTED 0
115 # define nsel_HAVE_STD_EXPECTED 0
118 #define nsel_USES_STD_EXPECTED ( (nsel_CONFIG_SELECT_EXPECTED == nsel_EXPECTED_STD) || ((nsel_CONFIG_SELECT_EXPECTED == nsel_EXPECTED_DEFAULT) && nsel_HAVE_STD_EXPECTED) )
121 // in_place: code duplicated in any-lite, expected-lite, expected-lite, value-ptr-lite, variant-lite:
124 #ifndef nonstd_lite_HAVE_IN_PLACE_TYPES
125 #define nonstd_lite_HAVE_IN_PLACE_TYPES 1
127 // C++17 std::in_place in <utility>:
129 #if nsel_CPP17_OR_GREATER
136 using std::in_place_type
;
137 using std::in_place_index
;
138 using std::in_place_t
;
139 using std::in_place_type_t
;
140 using std::in_place_index_t
;
142 #define nonstd_lite_in_place_t( T) std::in_place_t
143 #define nonstd_lite_in_place_type_t( T) std::in_place_type_t<T>
144 #define nonstd_lite_in_place_index_t(K) std::in_place_index_t<K>
146 #define nonstd_lite_in_place( T) std::in_place_t{}
147 #define nonstd_lite_in_place_type( T) std::in_place_type_t<T>{}
148 #define nonstd_lite_in_place_index(K) std::in_place_index_t<K>{}
150 } // namespace nonstd
152 #else // nsel_CPP17_OR_GREATER
160 struct in_place_type_tag
{};
162 template< std::size_t K
>
163 struct in_place_index_tag
{};
165 } // namespace detail
167 struct in_place_t
{};
170 inline in_place_t
in_place( detail::in_place_type_tag
<T
> = detail::in_place_type_tag
<T
>() )
175 template< std::size_t K
>
176 inline in_place_t
in_place( detail::in_place_index_tag
<K
> = detail::in_place_index_tag
<K
>() )
182 inline in_place_t
in_place_type( detail::in_place_type_tag
<T
> = detail::in_place_type_tag
<T
>() )
187 template< std::size_t K
>
188 inline in_place_t
in_place_index( detail::in_place_index_tag
<K
> = detail::in_place_index_tag
<K
>() )
193 // mimic templated typedef:
195 #define nonstd_lite_in_place_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag<T> )
196 #define nonstd_lite_in_place_type_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag<T> )
197 #define nonstd_lite_in_place_index_t(K) nonstd::in_place_t(&)( nonstd::detail::in_place_index_tag<K> )
199 #define nonstd_lite_in_place( T) nonstd::in_place_type<T>
200 #define nonstd_lite_in_place_type( T) nonstd::in_place_type<T>
201 #define nonstd_lite_in_place_index(K) nonstd::in_place_index<K>
203 } // namespace nonstd
205 #endif // nsel_CPP17_OR_GREATER
206 #endif // nonstd_lite_HAVE_IN_PLACE_TYPES
209 // Using std::expected:
212 #if nsel_USES_STD_EXPECTED
222 #else // nsel_USES_STD_EXPECTED
226 #include <functional>
227 #include <initializer_list>
230 #include <system_error>
231 #include <type_traits>
234 // additional includes:
236 #if nsel_CONFIG_NO_EXCEPTIONS
237 # if nsel_CONFIG_NO_EXCEPTIONS_SEH
238 # include <windows.h> // for ExceptionCodes
240 // already included: <cassert>
243 # include <stdexcept>
246 // C++ feature usage:
248 #if nsel_CPP11_OR_GREATER
249 # define nsel_constexpr constexpr
251 # define nsel_constexpr /*constexpr*/
254 #if nsel_CPP14_OR_GREATER
255 # define nsel_constexpr14 constexpr
257 # define nsel_constexpr14 /*constexpr*/
260 #if nsel_CPP17_OR_GREATER
261 # define nsel_inline17 inline
263 # define nsel_inline17 /*inline*/
266 // Compiler versions:
268 // MSVC++ 6.0 _MSC_VER == 1200 nsel_COMPILER_MSVC_VERSION == 60 (Visual Studio 6.0)
269 // MSVC++ 7.0 _MSC_VER == 1300 nsel_COMPILER_MSVC_VERSION == 70 (Visual Studio .NET 2002)
270 // MSVC++ 7.1 _MSC_VER == 1310 nsel_COMPILER_MSVC_VERSION == 71 (Visual Studio .NET 2003)
271 // MSVC++ 8.0 _MSC_VER == 1400 nsel_COMPILER_MSVC_VERSION == 80 (Visual Studio 2005)
272 // MSVC++ 9.0 _MSC_VER == 1500 nsel_COMPILER_MSVC_VERSION == 90 (Visual Studio 2008)
273 // MSVC++ 10.0 _MSC_VER == 1600 nsel_COMPILER_MSVC_VERSION == 100 (Visual Studio 2010)
274 // MSVC++ 11.0 _MSC_VER == 1700 nsel_COMPILER_MSVC_VERSION == 110 (Visual Studio 2012)
275 // MSVC++ 12.0 _MSC_VER == 1800 nsel_COMPILER_MSVC_VERSION == 120 (Visual Studio 2013)
276 // MSVC++ 14.0 _MSC_VER == 1900 nsel_COMPILER_MSVC_VERSION == 140 (Visual Studio 2015)
277 // MSVC++ 14.1 _MSC_VER >= 1910 nsel_COMPILER_MSVC_VERSION == 141 (Visual Studio 2017)
278 // MSVC++ 14.2 _MSC_VER >= 1920 nsel_COMPILER_MSVC_VERSION == 142 (Visual Studio 2019)
280 #if defined(_MSC_VER) && !defined(__clang__)
281 # define nsel_COMPILER_MSVC_VER (_MSC_VER )
282 # define nsel_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900)) )
284 # define nsel_COMPILER_MSVC_VER 0
285 # define nsel_COMPILER_MSVC_VERSION 0
288 #define nsel_COMPILER_VERSION( major, minor, patch ) ( 10 * ( 10 * (major) + (minor) ) + (patch) )
290 #if defined(__clang__)
291 # define nsel_COMPILER_CLANG_VERSION nsel_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__)
293 # define nsel_COMPILER_CLANG_VERSION 0
296 #if defined(__GNUC__) && !defined(__clang__)
297 # define nsel_COMPILER_GNUC_VERSION nsel_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
299 # define nsel_COMPILER_GNUC_VERSION 0
302 // half-open range [lo..hi):
303 //#define nsel_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) )
307 #define nsel_REQUIRES_0(...) \
308 template< bool B = (__VA_ARGS__), typename std::enable_if<B, int>::type = 0 >
310 #define nsel_REQUIRES_T(...) \
311 , typename std::enable_if< (__VA_ARGS__), int >::type = 0
313 #define nsel_REQUIRES_R(R, ...) \
314 typename std::enable_if< (__VA_ARGS__), R>::type
316 #define nsel_REQUIRES_A(...) \
317 , typename std::enable_if< (__VA_ARGS__), void*>::type = nullptr
319 // Presence of language and library features:
322 # define nsel_HAS_CPP0X _HAS_CPP0X
324 # define nsel_HAS_CPP0X 0
327 //#define nsel_CPP11_140 (nsel_CPP11_OR_GREATER || nsel_COMPILER_MSVC_VER >= 1900)
329 // Clang, GNUC, MSVC warning suppression macros:
332 # pragma clang diagnostic push
333 #elif defined __GNUC__
334 # pragma GCC diagnostic push
337 #if nsel_COMPILER_MSVC_VERSION >= 140
338 # pragma warning( push )
339 # define nsel_DISABLE_MSVC_WARNINGS(codes) __pragma( warning(disable: codes) )
341 # define nsel_DISABLE_MSVC_WARNINGS(codes)
345 # define nsel_RESTORE_WARNINGS() _Pragma("clang diagnostic pop")
346 #elif defined __GNUC__
347 # define nsel_RESTORE_WARNINGS() _Pragma("GCC diagnostic pop")
348 #elif nsel_COMPILER_MSVC_VERSION >= 140
349 # define nsel_RESTORE_WARNINGS() __pragma( warning( pop ) )
351 # define nsel_RESTORE_WARNINGS()
354 // Suppress the following MSVC (GSL) warnings:
355 // - C26409: Avoid calling new and delete explicitly, use std::make_unique<T> instead (r.11)
357 nsel_DISABLE_MSVC_WARNINGS( 26409 )
363 namespace nonstd
{ namespace expected_lite
{
365 // type traits C++17:
369 #if nsel_CPP17_OR_GREATER
371 using std::conjunction
;
372 using std::is_swappable
;
373 using std::is_nothrow_swappable
;
375 #else // nsel_CPP17_OR_GREATER
383 template< typename T
, typename
= decltype( swap( std::declval
<T
&>(), std::declval
<T
&>() ) ) >
384 static std::true_type
test( int /* unused */);
387 static std::false_type
test(...);
390 struct is_nothrow_swappable
392 // wrap noexcept(expr) in separate function as work-around for VC140 (VS2015):
394 template< typename T
>
395 static constexpr bool satisfies()
397 return noexcept( swap( std::declval
<T
&>(), std::declval
<T
&>() ) );
400 template< typename T
>
401 static auto test( int ) -> std::integral_constant
<bool, satisfies
<T
>()>{}
404 static auto test(...) -> std::false_type
;
406 } // namespace detail
408 // is [nothrow] swappable:
410 template< typename T
>
411 struct is_swappable
: decltype( detail::is_swappable::test
<T
>(0) ){};
413 template< typename T
>
414 struct is_nothrow_swappable
: decltype( detail::is_nothrow_swappable::test
<T
>(0) ){};
418 template< typename
... > struct conjunction
: std::true_type
{};
419 template< typename B1
> struct conjunction
<B1
> : B1
{};
421 template< typename B1
, typename
... Bn
>
422 struct conjunction
<B1
, Bn
...> : std::conditional
<bool(B1::value
), conjunction
<Bn
...>, B1
>::type
{};
424 #endif // nsel_CPP17_OR_GREATER
428 // type traits C++20:
432 #if defined(__cpp_lib_remove_cvref)
434 using std::remove_cvref
;
438 template< typename T
>
441 typedef typename
std::remove_cv
< typename
std::remove_reference
<T
>::type
>::type type
;
448 // forward declaration:
450 template< typename T
, typename E
>
455 /// discriminated union to hold value or 'error'.
457 template< typename T
, typename E
>
460 template< typename
, typename
> friend class nonstd::expected_lite::expected
;
463 using value_type
= T
;
464 using error_type
= E
;
466 // no-op construction
470 explicit storage_t_impl( bool has_value
)
471 : m_has_value( has_value
)
474 void construct_value( value_type
const & e
)
476 new( &m_value
) value_type( e
);
479 void construct_value( value_type
&& e
)
481 new( &m_value
) value_type( std::move( e
) );
484 template< class... Args
>
485 void emplace_value( Args
&&... args
)
487 new( &m_value
) value_type( std::forward
<Args
>(args
)...);
490 template< class U
, class... Args
>
491 void emplace_value( std::initializer_list
<U
> il
, Args
&&... args
)
493 new( &m_value
) value_type( il
, std::forward
<Args
>(args
)... );
496 void destruct_value()
498 m_value
.~value_type();
501 void construct_error( error_type
const & e
)
503 new( &m_error
) error_type( e
);
506 void construct_error( error_type
&& e
)
508 new( &m_error
) error_type( std::move( e
) );
511 template< class... Args
>
512 void emplace_error( Args
&&... args
)
514 new( &m_error
) error_type( std::forward
<Args
>(args
)...);
517 template< class U
, class... Args
>
518 void emplace_error( std::initializer_list
<U
> il
, Args
&&... args
)
520 new( &m_error
) error_type( il
, std::forward
<Args
>(args
)... );
523 void destruct_error()
525 m_error
.~error_type();
528 constexpr value_type
const & value() const &
533 value_type
& value() &
538 constexpr value_type
const && value() const &&
540 return std::move( m_value
);
543 nsel_constexpr14 value_type
&& value() &&
545 return std::move( m_value
);
548 value_type
const * value_ptr() const
553 value_type
* value_ptr()
558 error_type
const & error() const &
563 error_type
& error() &
568 constexpr error_type
const && error() const &&
570 return std::move( m_error
);
573 nsel_constexpr14 error_type
&& error() &&
575 return std::move( m_error
);
578 bool has_value() const
583 void set_has_value( bool v
)
595 bool m_has_value
= false;
598 /// discriminated union to hold only 'error'.
600 template< typename E
>
601 struct storage_t_impl
<void, E
>
603 template< typename
, typename
> friend class nonstd::expected_lite::expected
;
606 using value_type
= void;
607 using error_type
= E
;
609 // no-op construction
613 explicit storage_t_impl( bool has_value
)
614 : m_has_value( has_value
)
617 void construct_error( error_type
const & e
)
619 new( &m_error
) error_type( e
);
622 void construct_error( error_type
&& e
)
624 new( &m_error
) error_type( std::move( e
) );
627 template< class... Args
>
628 void emplace_error( Args
&&... args
)
630 new( &m_error
) error_type( std::forward
<Args
>(args
)...);
633 template< class U
, class... Args
>
634 void emplace_error( std::initializer_list
<U
> il
, Args
&&... args
)
636 new( &m_error
) error_type( il
, std::forward
<Args
>(args
)... );
639 void destruct_error()
641 m_error
.~error_type();
644 error_type
const & error() const &
649 error_type
& error() &
654 constexpr error_type
const && error() const &&
656 return std::move( m_error
);
659 nsel_constexpr14 error_type
&& error() &&
661 return std::move( m_error
);
664 bool has_value() const
669 void set_has_value( bool v
)
681 bool m_has_value
= false;
684 template< typename T
, typename E
, bool isConstructable
, bool isMoveable
>
688 storage_t() = default;
689 ~storage_t() = default;
691 explicit storage_t( bool has_value
)
692 : storage_t_impl
<T
, E
>( has_value
)
695 storage_t( storage_t
const & other
) = delete;
696 storage_t( storage_t
&& other
) = delete;
699 template< typename T
, typename E
>
700 class storage_t
<T
, E
, true, true> : public storage_t_impl
<T
, E
>
703 storage_t() = default;
704 ~storage_t() = default;
706 explicit storage_t( bool has_value
)
707 : storage_t_impl
<T
, E
>( has_value
)
710 storage_t( storage_t
const & other
)
711 : storage_t_impl
<T
, E
>( other
.has_value() )
713 if ( this->has_value() ) this->construct_value( other
.value() );
714 else this->construct_error( other
.error() );
717 storage_t(storage_t
&& other
)
718 : storage_t_impl
<T
, E
>( other
.has_value() )
720 if ( this->has_value() ) this->construct_value( std::move( other
.value() ) );
721 else this->construct_error( std::move( other
.error() ) );
725 template< typename E
>
726 class storage_t
<void, E
, true, true> : public storage_t_impl
<void, E
>
729 storage_t() = default;
730 ~storage_t() = default;
732 explicit storage_t( bool has_value
)
733 : storage_t_impl
<void, E
>( has_value
)
736 storage_t( storage_t
const & other
)
737 : storage_t_impl
<void, E
>( other
.has_value() )
739 if ( this->has_value() ) ;
740 else this->construct_error( other
.error() );
743 storage_t(storage_t
&& other
)
744 : storage_t_impl
<void, E
>( other
.has_value() )
746 if ( this->has_value() ) ;
747 else this->construct_error( std::move( other
.error() ) );
751 template< typename T
, typename E
>
752 class storage_t
<T
, E
, true, false> : public storage_t_impl
<T
, E
>
755 storage_t() = default;
756 ~storage_t() = default;
758 explicit storage_t( bool has_value
)
759 : storage_t_impl
<T
, E
>( has_value
)
762 storage_t( storage_t
const & other
)
763 : storage_t_impl
<T
, E
>(other
.has_value())
765 if ( this->has_value() ) this->construct_value( other
.value() );
766 else this->construct_error( other
.error() );
769 storage_t( storage_t
&& other
) = delete;
772 template< typename E
>
773 class storage_t
<void, E
, true, false> : public storage_t_impl
<void, E
>
776 storage_t() = default;
777 ~storage_t() = default;
779 explicit storage_t( bool has_value
)
780 : storage_t_impl
<void, E
>( has_value
)
783 storage_t( storage_t
const & other
)
784 : storage_t_impl
<void, E
>(other
.has_value())
786 if ( this->has_value() ) ;
787 else this->construct_error( other
.error() );
790 storage_t( storage_t
&& other
) = delete;
793 template< typename T
, typename E
>
794 class storage_t
<T
, E
, false, true> : public storage_t_impl
<T
, E
>
797 storage_t() = default;
798 ~storage_t() = default;
800 explicit storage_t( bool has_value
)
801 : storage_t_impl
<T
, E
>( has_value
)
804 storage_t( storage_t
const & other
) = delete;
806 storage_t( storage_t
&& other
)
807 : storage_t_impl
<T
, E
>( other
.has_value() )
809 if ( this->has_value() ) this->construct_value( std::move( other
.value() ) );
810 else this->construct_error( std::move( other
.error() ) );
814 template< typename E
>
815 class storage_t
<void, E
, false, true> : public storage_t_impl
<void, E
>
818 storage_t() = default;
819 ~storage_t() = default;
821 explicit storage_t( bool has_value
)
822 : storage_t_impl
<void, E
>( has_value
)
825 storage_t( storage_t
const & other
) = delete;
827 storage_t( storage_t
&& other
)
828 : storage_t_impl
<void, E
>( other
.has_value() )
830 if ( this->has_value() ) ;
831 else this->construct_error( std::move( other
.error() ) );
835 } // namespace detail
837 /// x.x.5 Unexpected object type; unexpected_type; C++17 and later can also use aliased type unexpected.
840 template< typename E
= std::exception_ptr
>
841 class unexpected_type
843 template< typename E
>
844 class unexpected_type
845 #endif // nsel_P0323R
848 using error_type
= E
;
850 // x.x.5.2.1 Constructors
852 // unexpected_type() = delete;
854 constexpr unexpected_type( unexpected_type
const & ) = default;
855 constexpr unexpected_type( unexpected_type
&& ) = default;
857 template< typename
... Args
859 std::is_constructible
<E
, Args
&&...>::value
862 constexpr explicit unexpected_type( nonstd_lite_in_place_t(E
), Args
&&... args
)
863 : m_error( std::forward
<Args
>( args
)...)
866 template< typename U
, typename
... Args
868 std::is_constructible
<E
, std::initializer_list
<U
>, Args
&&...>::value
871 constexpr explicit unexpected_type( nonstd_lite_in_place_t(E
), std::initializer_list
<U
> il
, Args
&&... args
)
872 : m_error( il
, std::forward
<Args
>( args
)...)
875 template< typename E2
877 std::is_constructible
<E
,E2
>::value
878 && !std::is_same
< typename
std20::remove_cvref
<E2
>::type
, nonstd_lite_in_place_t(E2
) >::value
879 && !std::is_same
< typename
std20::remove_cvref
<E2
>::type
, unexpected_type
>::value
882 constexpr explicit unexpected_type( E2
&& error
)
883 : m_error( std::forward
<E2
>( error
) )
886 template< typename E2
888 std::is_constructible
< E
, E2
>::value
889 && !std::is_constructible
<E
, unexpected_type
<E2
> & >::value
890 && !std::is_constructible
<E
, unexpected_type
<E2
> >::value
891 && !std::is_constructible
<E
, unexpected_type
<E2
> const & >::value
892 && !std::is_constructible
<E
, unexpected_type
<E2
> const >::value
893 && !std::is_convertible
< unexpected_type
<E2
> &, E
>::value
894 && !std::is_convertible
< unexpected_type
<E2
> , E
>::value
895 && !std::is_convertible
< unexpected_type
<E2
> const &, E
>::value
896 && !std::is_convertible
< unexpected_type
<E2
> const , E
>::value
897 && !std::is_convertible
< E2
const &, E
>::value
/*=> explicit */
900 constexpr explicit unexpected_type( unexpected_type
<E2
> const & error
)
901 : m_error( E
{ error
.value() } )
904 template< typename E2
906 std::is_constructible
< E
, E2
>::value
907 && !std::is_constructible
<E
, unexpected_type
<E2
> & >::value
908 && !std::is_constructible
<E
, unexpected_type
<E2
> >::value
909 && !std::is_constructible
<E
, unexpected_type
<E2
> const & >::value
910 && !std::is_constructible
<E
, unexpected_type
<E2
> const >::value
911 && !std::is_convertible
< unexpected_type
<E2
> &, E
>::value
912 && !std::is_convertible
< unexpected_type
<E2
> , E
>::value
913 && !std::is_convertible
< unexpected_type
<E2
> const &, E
>::value
914 && !std::is_convertible
< unexpected_type
<E2
> const , E
>::value
915 && std::is_convertible
< E2
const &, E
>::value
/*=> explicit */
918 constexpr /*non-explicit*/ unexpected_type( unexpected_type
<E2
> const & error
)
919 : m_error( error
.value() )
922 template< typename E2
924 std::is_constructible
< E
, E2
>::value
925 && !std::is_constructible
<E
, unexpected_type
<E2
> & >::value
926 && !std::is_constructible
<E
, unexpected_type
<E2
> >::value
927 && !std::is_constructible
<E
, unexpected_type
<E2
> const & >::value
928 && !std::is_constructible
<E
, unexpected_type
<E2
> const >::value
929 && !std::is_convertible
< unexpected_type
<E2
> &, E
>::value
930 && !std::is_convertible
< unexpected_type
<E2
> , E
>::value
931 && !std::is_convertible
< unexpected_type
<E2
> const &, E
>::value
932 && !std::is_convertible
< unexpected_type
<E2
> const , E
>::value
933 && !std::is_convertible
< E2
const &, E
>::value
/*=> explicit */
936 constexpr explicit unexpected_type( unexpected_type
<E2
> && error
)
937 : m_error( E
{ std::move( error
.value() ) } )
940 template< typename E2
942 std::is_constructible
< E
, E2
>::value
943 && !std::is_constructible
<E
, unexpected_type
<E2
> & >::value
944 && !std::is_constructible
<E
, unexpected_type
<E2
> >::value
945 && !std::is_constructible
<E
, unexpected_type
<E2
> const & >::value
946 && !std::is_constructible
<E
, unexpected_type
<E2
> const >::value
947 && !std::is_convertible
< unexpected_type
<E2
> &, E
>::value
948 && !std::is_convertible
< unexpected_type
<E2
> , E
>::value
949 && !std::is_convertible
< unexpected_type
<E2
> const &, E
>::value
950 && !std::is_convertible
< unexpected_type
<E2
> const , E
>::value
951 && std::is_convertible
< E2
const &, E
>::value
/*=> non-explicit */
954 constexpr /*non-explicit*/ unexpected_type( unexpected_type
<E2
> && error
)
955 : m_error( std::move( error
.value() ) )
958 // x.x.5.2.2 Assignment
960 nsel_constexpr14 unexpected_type
& operator=( unexpected_type
const & ) = default;
961 nsel_constexpr14 unexpected_type
& operator=( unexpected_type
&& ) = default;
963 template< typename E2
= E
>
964 nsel_constexpr14 unexpected_type
& operator=( unexpected_type
<E2
> const & other
)
966 unexpected_type
{ other
.value() }.swap( *this );
970 template< typename E2
= E
>
971 nsel_constexpr14 unexpected_type
& operator=( unexpected_type
<E2
> && other
)
973 unexpected_type
{ std::move( other
.value() ) }.swap( *this );
977 // x.x.5.2.3 Observers
979 nsel_constexpr14 E
& value() & noexcept
984 constexpr E
const & value() const & noexcept
989 #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490
991 nsel_constexpr14 E
&& value() && noexcept
993 return std::move( m_error
);
996 constexpr E
const && value() const && noexcept
998 return std::move( m_error
);
1005 template< typename U
=E
>
1006 nsel_REQUIRES_R( void,
1007 std17::is_swappable
<U
>::value
1009 swap( unexpected_type
& other
) noexcept (
1010 std17::is_nothrow_swappable
<U
>::value
1014 swap( m_error
, other
.m_error
);
1017 // TODO: ??? unexpected_type: in-class friend operator==, !=
1023 #if nsel_CPP17_OR_GREATER
1025 /// template deduction guide:
1027 template< typename E
>
1028 unexpected_type( E
) -> unexpected_type
< E
>;
1032 /// class unexpected_type, std::exception_ptr specialization (P0323R2)
1034 #if !nsel_CONFIG_NO_EXCEPTIONS
1035 #if nsel_P0323R <= 2
1037 // TODO: Should expected be specialized for particular E types such as exception_ptr and how?
1038 // See p0323r7 2.1. Ergonomics, http://wg21.link/p0323
1040 class unexpected_type
< std::exception_ptr
>
1043 using error_type
= std::exception_ptr
;
1045 unexpected_type() = delete;
1047 ~unexpected_type(){}
1049 explicit unexpected_type( std::exception_ptr
const & error
)
1053 explicit unexpected_type(std::exception_ptr
&& error
)
1054 : m_error( std::move( error
) )
1057 template< typename E
>
1058 explicit unexpected_type( E error
)
1059 : m_error( std::make_exception_ptr( error
) )
1062 std::exception_ptr
const & value() const
1067 std::exception_ptr
& value()
1073 std::exception_ptr m_error
;
1076 #endif // nsel_P0323R
1077 #endif // !nsel_CONFIG_NO_EXCEPTIONS
1079 /// x.x.4, Unexpected equality operators
1081 template< typename E1
, typename E2
>
1082 constexpr bool operator==( unexpected_type
<E1
> const & x
, unexpected_type
<E2
> const & y
)
1084 return x
.value() == y
.value();
1087 template< typename E1
, typename E2
>
1088 constexpr bool operator!=( unexpected_type
<E1
> const & x
, unexpected_type
<E2
> const & y
)
1090 return ! ( x
== y
);
1093 #if nsel_P0323R <= 2
1095 template< typename E
>
1096 constexpr bool operator<( unexpected_type
<E
> const & x
, unexpected_type
<E
> const & y
)
1098 return x
.value() < y
.value();
1101 template< typename E
>
1102 constexpr bool operator>( unexpected_type
<E
> const & x
, unexpected_type
<E
> const & y
)
1107 template< typename E
>
1108 constexpr bool operator<=( unexpected_type
<E
> const & x
, unexpected_type
<E
> const & y
)
1113 template< typename E
>
1114 constexpr bool operator>=( unexpected_type
<E
> const & x
, unexpected_type
<E
> const & y
)
1119 #endif // nsel_P0323R
1121 /// x.x.5 Specialized algorithms
1123 template< typename E
1125 std17::is_swappable
<E
>::value
1128 void swap( unexpected_type
<E
> & x
, unexpected_type
<E
> & y
) noexcept ( noexcept ( x
.swap(y
) ) )
1133 #if nsel_P0323R <= 2
1135 // unexpected: relational operators for std::exception_ptr:
1137 inline constexpr bool operator<( unexpected_type
<std::exception_ptr
> const & /*x*/, unexpected_type
<std::exception_ptr
> const & /*y*/ )
1142 inline constexpr bool operator>( unexpected_type
<std::exception_ptr
> const & /*x*/, unexpected_type
<std::exception_ptr
> const & /*y*/ )
1147 inline constexpr bool operator<=( unexpected_type
<std::exception_ptr
> const & x
, unexpected_type
<std::exception_ptr
> const & y
)
1152 inline constexpr bool operator>=( unexpected_type
<std::exception_ptr
> const & x
, unexpected_type
<std::exception_ptr
> const & y
)
1157 #endif // nsel_P0323R
1159 // unexpected: traits
1161 #if nsel_P0323R <= 3
1163 template< typename E
>
1164 struct is_unexpected
: std::false_type
{};
1166 template< typename E
>
1167 struct is_unexpected
< unexpected_type
<E
> > : std::true_type
{};
1169 #endif // nsel_P0323R
1171 // unexpected: factory
1173 // keep make_unexpected() removed in p0323r2 for pre-C++17:
1175 template< typename E
>
1176 nsel_constexpr14
auto
1177 make_unexpected( E
&& value
) -> unexpected_type
< typename
std::decay
<E
>::type
>
1179 return unexpected_type
< typename
std::decay
<E
>::type
>( std::forward
<E
>(value
) );
1182 #if nsel_P0323R <= 3
1184 /*nsel_constexpr14*/ auto inline
1185 make_unexpected_from_current_exception() -> unexpected_type
< std::exception_ptr
>
1187 return unexpected_type
< std::exception_ptr
>( std::current_exception() );
1190 #endif // nsel_P0323R
1192 /// x.x.6, x.x.7 expected access error
1194 template< typename E
>
1195 class bad_expected_access
;
1197 /// x.x.7 bad_expected_access<void>: expected access error
1200 class bad_expected_access
< void > : public std::exception
1203 explicit bad_expected_access()
1208 /// x.x.6 bad_expected_access: expected access error
1210 #if !nsel_CONFIG_NO_EXCEPTIONS
1212 template< typename E
>
1213 class bad_expected_access
: public bad_expected_access
< void >
1216 using error_type
= E
;
1218 explicit bad_expected_access( error_type error
)
1222 virtual char const * what() const noexcept override
1224 return "bad_expected_access";
1227 nsel_constexpr14 error_type
& error() &
1232 constexpr error_type
const & error() const &
1237 #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490
1239 nsel_constexpr14 error_type
&& error() &&
1241 return std::move( m_error
);
1244 constexpr error_type
const && error() const &&
1246 return std::move( m_error
);
1255 #endif // nsel_CONFIG_NO_EXCEPTIONS
1257 /// x.x.8 unexpect tag, in_place_unexpected tag: construct an error
1259 struct unexpect_t
{};
1260 using in_place_unexpected_t
= unexpect_t
;
1262 nsel_inline17
constexpr unexpect_t unexpect
{};
1263 nsel_inline17
constexpr unexpect_t in_place_unexpected
{};
1265 /// class error_traits
1267 #if nsel_CONFIG_NO_EXCEPTIONS
1270 inline bool text( char const * /*text*/ ) { return true; }
1273 template< typename Error
>
1276 static void rethrow( Error
const & /*e*/ )
1278 #if nsel_CONFIG_NO_EXCEPTIONS_SEH
1279 RaiseException( EXCEPTION_ACCESS_VIOLATION
, EXCEPTION_NONCONTINUABLE
, 0, NULL
);
1281 assert( false && detail::text("throw bad_expected_access<Error>{ e };") );
1287 struct error_traits
< std::exception_ptr
>
1289 static void rethrow( std::exception_ptr
const & /*e*/ )
1291 #if nsel_CONFIG_NO_EXCEPTIONS_SEH
1292 RaiseException( EXCEPTION_ACCESS_VIOLATION
, EXCEPTION_NONCONTINUABLE
, 0, NULL
);
1294 assert( false && detail::text("throw bad_expected_access<std::exception_ptr>{ e };") );
1300 struct error_traits
< std::error_code
>
1302 static void rethrow( std::error_code
const & /*e*/ )
1304 #if nsel_CONFIG_NO_EXCEPTIONS_SEH
1305 RaiseException( EXCEPTION_ACCESS_VIOLATION
, EXCEPTION_NONCONTINUABLE
, 0, NULL
);
1307 assert( false && detail::text("throw std::system_error( e );") );
1312 #else // nsel_CONFIG_NO_EXCEPTIONS
1314 template< typename Error
>
1317 static void rethrow( Error
const & e
)
1319 throw bad_expected_access
<Error
>{ e
};
1324 struct error_traits
< std::exception_ptr
>
1326 static void rethrow( std::exception_ptr
const & e
)
1328 std::rethrow_exception( e
);
1333 struct error_traits
< std::error_code
>
1335 static void rethrow( std::error_code
const & e
)
1337 throw std::system_error( e
);
1341 #endif // nsel_CONFIG_NO_EXCEPTIONS
1343 } // namespace expected_lite
1345 // provide nonstd::unexpected_type:
1347 using expected_lite::unexpected_type
;
1349 namespace expected_lite
{
1353 #if nsel_P0323R <= 2
1354 template< typename T
, typename E
= std::exception_ptr
>
1357 template< typename T
, typename E
>
1359 #endif // nsel_P0323R
1362 template< typename
, typename
> friend class expected
;
1365 using value_type
= T
;
1366 using error_type
= E
;
1367 using unexpected_type
= nonstd::unexpected_type
<E
>;
1369 template< typename U
>
1372 using type
= expected
<U
, error_type
>;
1375 // x.x.4.1 constructors
1378 std::is_default_constructible
<T
>::value
1380 nsel_constexpr14
expected()
1383 contained
.construct_value( value_type() );
1386 nsel_constexpr14
expected( expected
const & ) = default;
1387 nsel_constexpr14
expected( expected
&& ) = default;
1389 template< typename U
, typename G
1391 std::is_constructible
< T
, U
const &>::value
1392 && std::is_constructible
<E
, G
const &>::value
1393 && !std::is_constructible
<T
, expected
<U
, G
> & >::value
1394 && !std::is_constructible
<T
, expected
<U
, G
> && >::value
1395 && !std::is_constructible
<T
, expected
<U
, G
> const & >::value
1396 && !std::is_constructible
<T
, expected
<U
, G
> const && >::value
1397 && !std::is_convertible
< expected
<U
, G
> & , T
>::value
1398 && !std::is_convertible
< expected
<U
, G
> &&, T
>::value
1399 && !std::is_convertible
< expected
<U
, G
> const & , T
>::value
1400 && !std::is_convertible
< expected
<U
, G
> const &&, T
>::value
1401 && (!std::is_convertible
<U
const &, T
>::value
|| !std::is_convertible
<G
const &, E
>::value
) /*=> explicit */
1404 nsel_constexpr14
explicit expected( expected
<U
, G
> const & other
)
1405 : contained( other
.has_value() )
1407 if ( has_value() ) contained
.construct_value( T
{ other
.contained
.value() } );
1408 else contained
.construct_error( E
{ other
.contained
.error() } );
1411 template< typename U
, typename G
1413 std::is_constructible
< T
, U
const &>::value
1414 && std::is_constructible
<E
, G
const &>::value
1415 && !std::is_constructible
<T
, expected
<U
, G
> & >::value
1416 && !std::is_constructible
<T
, expected
<U
, G
> && >::value
1417 && !std::is_constructible
<T
, expected
<U
, G
> const & >::value
1418 && !std::is_constructible
<T
, expected
<U
, G
> const && >::value
1419 && !std::is_convertible
< expected
<U
, G
> & , T
>::value
1420 && !std::is_convertible
< expected
<U
, G
> &&, T
>::value
1421 && !std::is_convertible
< expected
<U
, G
> const &, T
>::value
1422 && !std::is_convertible
< expected
<U
, G
> const &&, T
>::value
1423 && !(!std::is_convertible
<U
const &, T
>::value
|| !std::is_convertible
<G
const &, E
>::value
) /*=> non-explicit */
1426 nsel_constexpr14
/*non-explicit*/ expected( expected
<U
, G
> const & other
)
1427 : contained( other
.has_value() )
1429 if ( has_value() ) contained
.construct_value( other
.contained
.value() );
1430 else contained
.construct_error( other
.contained
.error() );
1433 template< typename U
, typename G
1435 std::is_constructible
< T
, U
>::value
1436 && std::is_constructible
<E
, G
>::value
1437 && !std::is_constructible
<T
, expected
<U
, G
> & >::value
1438 && !std::is_constructible
<T
, expected
<U
, G
> && >::value
1439 && !std::is_constructible
<T
, expected
<U
, G
> const & >::value
1440 && !std::is_constructible
<T
, expected
<U
, G
> const && >::value
1441 && !std::is_convertible
< expected
<U
, G
> & , T
>::value
1442 && !std::is_convertible
< expected
<U
, G
> &&, T
>::value
1443 && !std::is_convertible
< expected
<U
, G
> const & , T
>::value
1444 && !std::is_convertible
< expected
<U
, G
> const &&, T
>::value
1445 && (!std::is_convertible
<U
, T
>::value
|| !std::is_convertible
<G
, E
>::value
) /*=> explicit */
1448 nsel_constexpr14
explicit expected( expected
<U
, G
> && other
)
1449 : contained( other
.has_value() )
1451 if ( has_value() ) contained
.construct_value( T
{ std::move( other
.contained
.value() ) } );
1452 else contained
.construct_error( E
{ std::move( other
.contained
.error() ) } );
1455 template< typename U
, typename G
1457 std::is_constructible
< T
, U
>::value
1458 && std::is_constructible
<E
, G
>::value
1459 && !std::is_constructible
<T
, expected
<U
, G
> & >::value
1460 && !std::is_constructible
<T
, expected
<U
, G
> && >::value
1461 && !std::is_constructible
<T
, expected
<U
, G
> const & >::value
1462 && !std::is_constructible
<T
, expected
<U
, G
> const && >::value
1463 && !std::is_convertible
< expected
<U
, G
> & , T
>::value
1464 && !std::is_convertible
< expected
<U
, G
> &&, T
>::value
1465 && !std::is_convertible
< expected
<U
, G
> const & , T
>::value
1466 && !std::is_convertible
< expected
<U
, G
> const &&, T
>::value
1467 && !(!std::is_convertible
<U
, T
>::value
|| !std::is_convertible
<G
, E
>::value
) /*=> non-explicit */
1470 nsel_constexpr14
/*non-explicit*/ expected( expected
<U
, G
> && other
)
1471 : contained( other
.has_value() )
1473 if ( has_value() ) contained
.construct_value( std::move( other
.contained
.value() ) );
1474 else contained
.construct_error( std::move( other
.contained
.error() ) );
1477 template< typename U
= T
1479 std::is_copy_constructible
<U
>::value
1482 nsel_constexpr14
expected( value_type
const & value
)
1485 contained
.construct_value( value
);
1488 template< typename U
= T
1490 std::is_constructible
<T
,U
&&>::value
1491 && !std::is_same
<typename
std20::remove_cvref
<U
>::type
, nonstd_lite_in_place_t(U
)>::value
1492 && !std::is_same
< expected
<T
,E
> , typename
std20::remove_cvref
<U
>::type
>::value
1493 && !std::is_same
<nonstd::unexpected_type
<E
>, typename
std20::remove_cvref
<U
>::type
>::value
1494 && !std::is_convertible
<U
&&,T
>::value
/*=> explicit */
1497 nsel_constexpr14
explicit expected( U
&& value
) noexcept
1499 std::is_nothrow_move_constructible
<U
>::value
&&
1500 std::is_nothrow_move_constructible
<E
>::value
1504 contained
.construct_value( T
{ std::forward
<U
>( value
) } );
1507 template< typename U
= T
1509 std::is_constructible
<T
,U
&&>::value
1510 && !std::is_same
<typename
std20::remove_cvref
<U
>::type
, nonstd_lite_in_place_t(U
)>::value
1511 && !std::is_same
< expected
<T
,E
> , typename
std20::remove_cvref
<U
>::type
>::value
1512 && !std::is_same
<nonstd::unexpected_type
<E
>, typename
std20::remove_cvref
<U
>::type
>::value
1513 && std::is_convertible
<U
&&,T
>::value
/*=> non-explicit */
1516 nsel_constexpr14
/*non-explicit*/ expected( U
&& value
) noexcept
1518 std::is_nothrow_move_constructible
<U
>::value
&&
1519 std::is_nothrow_move_constructible
<E
>::value
1523 contained
.construct_value( std::forward
<U
>( value
) );
1528 template< typename G
= E
1530 std::is_constructible
<E
, G
const & >::value
1531 && !std::is_convertible
< G
const &, E
>::value
/*=> explicit */
1534 nsel_constexpr14
explicit expected( nonstd::unexpected_type
<G
> const & error
)
1535 : contained( false )
1537 contained
.construct_error( E
{ error
.value() } );
1540 template< typename G
= E
1542 std::is_constructible
<E
, G
const & >::value
1543 && std::is_convertible
< G
const &, E
>::value
/*=> non-explicit */
1546 nsel_constexpr14
/*non-explicit*/ expected( nonstd::unexpected_type
<G
> const & error
)
1547 : contained( false )
1549 contained
.construct_error( error
.value() );
1552 template< typename G
= E
1554 std::is_constructible
<E
, G
&& >::value
1555 && !std::is_convertible
< G
&&, E
>::value
/*=> explicit */
1558 nsel_constexpr14
explicit expected( nonstd::unexpected_type
<G
> && error
)
1559 : contained( false )
1561 contained
.construct_error( E
{ std::move( error
.value() ) } );
1564 template< typename G
= E
1566 std::is_constructible
<E
, G
&& >::value
1567 && std::is_convertible
< G
&&, E
>::value
/*=> non-explicit */
1570 nsel_constexpr14
/*non-explicit*/ expected( nonstd::unexpected_type
<G
> && error
)
1571 : contained( false )
1573 contained
.construct_error( std::move( error
.value() ) );
1576 // in-place construction, value
1578 template< typename
... Args
1580 std::is_constructible
<T
, Args
&&...>::value
1583 nsel_constexpr14
explicit expected( nonstd_lite_in_place_t(T
), Args
&&... args
)
1586 contained
.emplace_value( std::forward
<Args
>( args
)... );
1589 template< typename U
, typename
... Args
1591 std::is_constructible
<T
, std::initializer_list
<U
>, Args
&&...>::value
1594 nsel_constexpr14
explicit expected( nonstd_lite_in_place_t(T
), std::initializer_list
<U
> il
, Args
&&... args
)
1597 contained
.emplace_value( il
, std::forward
<Args
>( args
)... );
1600 // in-place construction, error
1602 template< typename
... Args
1604 std::is_constructible
<E
, Args
&&...>::value
1607 nsel_constexpr14
explicit expected( unexpect_t
, Args
&&... args
)
1608 : contained( false )
1610 contained
.emplace_error( std::forward
<Args
>( args
)... );
1613 template< typename U
, typename
... Args
1615 std::is_constructible
<E
, std::initializer_list
<U
>, Args
&&...>::value
1618 nsel_constexpr14
explicit expected( unexpect_t
, std::initializer_list
<U
> il
, Args
&&... args
)
1619 : contained( false )
1621 contained
.emplace_error( il
, std::forward
<Args
>( args
)... );
1624 // x.x.4.2 destructor
1626 // TODO: ~expected: triviality
1627 // Effects: If T is not cv void and is_trivially_destructible_v<T> is false and bool(*this), calls val.~T(). If is_trivially_destructible_v<E> is false and !bool(*this), calls unexpect.~unexpected<E>().
1628 // Remarks: If either T is cv void or is_trivially_destructible_v<T> is true, and is_trivially_destructible_v<E> is true, then this destructor shall be a trivial destructor.
1632 if ( has_value() ) contained
.destruct_value();
1633 else contained
.destruct_error();
1636 // x.x.4.3 assignment
1638 expected
& operator=( expected
const & other
)
1640 expected( other
).swap( *this );
1644 expected
& operator=( expected
&& other
) noexcept
1646 std::is_nothrow_move_constructible
< T
>::value
1647 && std::is_nothrow_move_assignable
< T
>::value
1648 && std::is_nothrow_move_constructible
<E
>::value
// added for missing
1649 && std::is_nothrow_move_assignable
< E
>::value
) // nothrow above
1651 expected( std::move( other
) ).swap( *this );
1655 template< typename U
1657 !std::is_same
<expected
<T
,E
>, typename
std20::remove_cvref
<U
>::type
>::value
1658 && std17::conjunction
<std::is_scalar
<T
>, std::is_same
<T
, std::decay
<U
>> >::value
1659 && std::is_constructible
<T
,U
>::value
1660 && std::is_assignable
< T
&,U
>::value
1661 && std::is_nothrow_move_constructible
<E
>::value
)
1663 expected
& operator=( U
&& value
)
1665 expected( std::forward
<U
>( value
) ).swap( *this );
1669 template< typename G
= E
1671 std::is_constructible
<E
, G
const&>::value
&&
1672 std::is_copy_constructible
<G
>::value
// TODO: std::is_nothrow_copy_constructible<G>
1673 && std::is_copy_assignable
<G
>::value
1676 expected
& operator=( nonstd::unexpected_type
<G
> const & error
)
1678 expected( unexpect
, error
.value() ).swap( *this );
1682 template< typename G
= E
1684 std::is_constructible
<E
, G
&&>::value
&&
1685 std::is_move_constructible
<G
>::value
// TODO: std::is_nothrow_move_constructible<G>
1686 && std::is_move_assignable
<G
>::value
1689 expected
& operator=( nonstd::unexpected_type
<G
> && error
)
1691 expected( unexpect
, std::move( error
.value() ) ).swap( *this );
1695 template< typename
... Args
1697 std::is_nothrow_constructible
<T
, Args
&&...>::value
1700 value_type
& emplace( Args
&&... args
)
1702 expected( nonstd_lite_in_place(T
), std::forward
<Args
>(args
)... ).swap( *this );
1706 template< typename U
, typename
... Args
1708 std::is_nothrow_constructible
<T
, std::initializer_list
<U
>&, Args
&&...>::value
1711 value_type
& emplace( std::initializer_list
<U
> il
, Args
&&... args
)
1713 expected( nonstd_lite_in_place(T
), il
, std::forward
<Args
>(args
)... ).swap( *this );
1719 template< typename U
=T
, typename G
=E
>
1720 nsel_REQUIRES_R( void,
1721 std17::is_swappable
< U
>::value
1722 && std17::is_swappable
<G
>::value
1723 && ( std::is_move_constructible
<U
>::value
|| std::is_move_constructible
<G
>::value
)
1725 swap( expected
& other
) noexcept
1727 std::is_nothrow_move_constructible
<T
>::value
&& std17::is_nothrow_swappable
<T
&>::value
&&
1728 std::is_nothrow_move_constructible
<E
>::value
&& std17::is_nothrow_swappable
<E
&>::value
1733 if ( bool(*this) && bool(other
) ) { swap( contained
.value(), other
.contained
.value() ); }
1734 else if ( ! bool(*this) && ! bool(other
) ) { swap( contained
.error(), other
.contained
.error() ); }
1735 else if ( bool(*this) && ! bool(other
) ) { error_type
t( std::move( other
.error() ) );
1736 other
.contained
.destruct_error();
1737 other
.contained
.construct_value( std::move( contained
.value() ) );
1738 contained
.destruct_value();
1739 contained
.construct_error( std::move( t
) );
1740 bool has_value
= contained
.has_value();
1741 bool other_has_value
= other
.has_value();
1742 other
.contained
.set_has_value(has_value
);
1743 contained
.set_has_value(other_has_value
);
1745 else if ( ! bool(*this) && bool(other
) ) { other
.swap( *this ); }
1748 // x.x.4.5 observers
1750 constexpr value_type
const * operator ->() const
1752 return assert( has_value() ), contained
.value_ptr();
1755 value_type
* operator ->()
1757 return assert( has_value() ), contained
.value_ptr();
1760 constexpr value_type
const & operator *() const &
1762 return assert( has_value() ), contained
.value();
1765 value_type
& operator *() &
1767 return assert( has_value() ), contained
.value();
1770 #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490
1772 constexpr value_type
const && operator *() const &&
1774 return std::move( ( assert( has_value() ), contained
.value() ) );
1777 nsel_constexpr14 value_type
&& operator *() &&
1779 return std::move( ( assert( has_value() ), contained
.value() ) );
1784 constexpr explicit operator bool() const noexcept
1789 constexpr bool has_value() const noexcept
1791 return contained
.has_value();
1794 constexpr value_type
const & value() const &
1797 ? ( contained
.value() )
1798 : ( error_traits
<error_type
>::rethrow( contained
.error() ), contained
.value() );
1801 value_type
& value() &
1804 ? ( contained
.value() )
1805 : ( error_traits
<error_type
>::rethrow( contained
.error() ), contained
.value() );
1808 #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490
1810 constexpr value_type
const && value() const &&
1812 return std::move( has_value()
1813 ? ( contained
.value() )
1814 : ( error_traits
<error_type
>::rethrow( contained
.error() ), contained
.value() ) );
1817 nsel_constexpr14 value_type
&& value() &&
1819 return std::move( has_value()
1820 ? ( contained
.value() )
1821 : ( error_traits
<error_type
>::rethrow( contained
.error() ), contained
.value() ) );
1826 constexpr error_type
const & error() const &
1828 return assert( ! has_value() ), contained
.error();
1831 error_type
& error() &
1833 return assert( ! has_value() ), contained
.error();
1836 #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490
1838 constexpr error_type
const && error() const &&
1840 return std::move( ( assert( ! has_value() ), contained
.error() ) );
1843 error_type
&& error() &&
1845 return std::move( ( assert( ! has_value() ), contained
.error() ) );
1850 constexpr unexpected_type
get_unexpected() const
1852 return make_unexpected( contained
.error() );
1855 template< typename Ex
>
1856 bool has_exception() const
1858 using ContainedEx
= typename
std::remove_reference
< decltype( get_unexpected().value() ) >::type
;
1859 return ! has_value() && std::is_base_of
< Ex
, ContainedEx
>::value
;
1862 template< typename U
1864 std::is_copy_constructible
< T
>::value
1865 && std::is_convertible
<U
&&, T
>::value
1868 value_type
value_or( U
&& v
) const &
1872 : static_cast<T
>( std::forward
<U
>( v
) );
1875 template< typename U
1877 std::is_move_constructible
< T
>::value
1878 && std::is_convertible
<U
&&, T
>::value
1881 value_type
value_or( U
&& v
) &&
1884 ? std::move( contained
.value() )
1885 : static_cast<T
>( std::forward
<U
>( v
) );
1890 // template <class U, class E>
1891 // constexpr expected<U,E> expected<expected<U,E>,E>::unwrap() const&;
1893 // template <class T, class E>
1894 // constexpr expected<T,E> expected<T,E>::unwrap() const&;
1896 // template <class U, class E>
1897 // expected<U,E> expected<expected<U,E>, E>::unwrap() &&;
1899 // template <class T, class E>
1900 // template expected<T,E> expected<T,E>::unwrap() &&;
1904 // template< typename Ex, typename F>
1905 // expected<T,E> catch_exception(F&& f);
1907 // template< typename F>
1908 // expected<decltype(func(declval<T>())),E> map(F&& func) ;
1910 // template< typename F>
1911 // 'see below' bind(F&& func);
1913 // template< typename F>
1914 // expected<T,E> catch_error(F&& f);
1916 // template< typename F>
1917 // 'see below' then(F&& func);
1924 , std::is_copy_constructible
<T
>::value
&& std::is_copy_constructible
<E
>::value
1925 , std::is_move_constructible
<T
>::value
&& std::is_move_constructible
<E
>::value
1930 /// class expected, void specialization
1932 template< typename E
>
1933 class expected
<void, E
>
1936 template< typename
, typename
> friend class expected
;
1939 using value_type
= void;
1940 using error_type
= E
;
1941 using unexpected_type
= nonstd::unexpected_type
<E
>;
1943 // x.x.4.1 constructors
1945 constexpr expected() noexcept
1949 nsel_constexpr14
expected( expected
const & other
) = default;
1950 nsel_constexpr14
expected( expected
&& other
) = default;
1952 constexpr explicit expected( nonstd_lite_in_place_t(void) )
1956 template< typename G
= E
1958 !std::is_convertible
<G
const &, E
>::value
/*=> explicit */
1961 nsel_constexpr14
explicit expected( nonstd::unexpected_type
<G
> const & error
)
1962 : contained( false )
1964 contained
.construct_error( E
{ error
.value() } );
1967 template< typename G
= E
1969 std::is_convertible
<G
const &, E
>::value
/*=> non-explicit */
1972 nsel_constexpr14
/*non-explicit*/ expected( nonstd::unexpected_type
<G
> const & error
)
1973 : contained( false )
1975 contained
.construct_error( error
.value() );
1978 template< typename G
= E
1980 !std::is_convertible
<G
&&, E
>::value
/*=> explicit */
1983 nsel_constexpr14
explicit expected( nonstd::unexpected_type
<G
> && error
)
1984 : contained( false )
1986 contained
.construct_error( E
{ std::move( error
.value() ) } );
1989 template< typename G
= E
1991 std::is_convertible
<G
&&, E
>::value
/*=> non-explicit */
1994 nsel_constexpr14
/*non-explicit*/ expected( nonstd::unexpected_type
<G
> && error
)
1995 : contained( false )
1997 contained
.construct_error( std::move( error
.value() ) );
2000 template< typename
... Args
2002 std::is_constructible
<E
, Args
&&...>::value
2005 nsel_constexpr14
explicit expected( unexpect_t
, Args
&&... args
)
2006 : contained( false )
2008 contained
.emplace_error( std::forward
<Args
>( args
)... );
2011 template< typename U
, typename
... Args
2013 std::is_constructible
<E
, std::initializer_list
<U
>, Args
&&...>::value
2016 nsel_constexpr14
explicit expected( unexpect_t
, std::initializer_list
<U
> il
, Args
&&... args
)
2017 : contained( false )
2019 contained
.emplace_error( il
, std::forward
<Args
>( args
)... );
2026 if ( ! has_value() )
2028 contained
.destruct_error();
2032 // x.x.4.3 assignment
2034 expected
& operator=( expected
const & other
)
2036 expected( other
).swap( *this );
2040 expected
& operator=( expected
&& other
) noexcept
2042 std::is_nothrow_move_assignable
<E
>::value
&&
2043 std::is_nothrow_move_constructible
<E
>::value
)
2045 expected( std::move( other
) ).swap( *this );
2051 expected().swap( *this );
2056 template< typename G
= E
>
2057 nsel_REQUIRES_R( void,
2058 std17::is_swappable
<G
>::value
2059 && std::is_move_constructible
<G
>::value
2061 swap( expected
& other
) noexcept
2063 std::is_nothrow_move_constructible
<E
>::value
&& std17::is_nothrow_swappable
<E
&>::value
2068 if ( ! bool(*this) && ! bool(other
) ) { swap( contained
.error(), other
.contained
.error() ); }
2069 else if ( bool(*this) && ! bool(other
) ) { contained
.construct_error( std::move( other
.error() ) );
2070 bool has_value
= contained
.has_value();
2071 bool other_has_value
= other
.has_value();
2072 other
.contained
.set_has_value(has_value
);
2073 contained
.set_has_value(other_has_value
);
2075 else if ( ! bool(*this) && bool(other
) ) { other
.swap( *this ); }
2078 // x.x.4.5 observers
2080 constexpr explicit operator bool() const noexcept
2085 constexpr bool has_value() const noexcept
2087 return contained
.has_value();
2092 if ( ! has_value() )
2094 error_traits
<error_type
>::rethrow( contained
.error() );
2098 constexpr error_type
const & error() const &
2100 return assert( ! has_value() ), contained
.error();
2103 error_type
& error() &
2105 return assert( ! has_value() ), contained
.error();
2108 #if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490
2110 constexpr error_type
const && error() const &&
2112 return std::move( ( assert( ! has_value() ), contained
.error() ) );
2115 error_type
&& error() &&
2117 return std::move( ( assert( ! has_value() ), contained
.error() ) );
2122 constexpr unexpected_type
get_unexpected() const
2124 return make_unexpected( contained
.error() );
2127 template< typename Ex
>
2128 bool has_exception() const
2130 using ContainedEx
= typename
std::remove_reference
< decltype( get_unexpected().value() ) >::type
;
2131 return ! has_value() && std::is_base_of
< Ex
, ContainedEx
>::value
;
2134 // template constexpr 'see below' unwrap() const&;
2136 // template 'see below' unwrap() &&;
2140 // template< typename Ex, typename F>
2141 // expected<void,E> catch_exception(F&& f);
2143 // template< typename F>
2144 // expected<decltype(func()), E> map(F&& func) ;
2146 // template< typename F>
2147 // 'see below' bind(F&& func) ;
2149 // template< typename F>
2150 // expected<void,E> catch_error(F&& f);
2152 // template< typename F>
2153 // 'see below' then(F&& func);
2160 , std::is_copy_constructible
<E
>::value
2161 , std::is_move_constructible
<E
>::value
2166 // x.x.4.6 expected<>: comparison operators
2168 template< typename T1
, typename E1
, typename T2
, typename E2
2170 !std::is_void
<T1
>::value
&& !std::is_void
<T2
>::value
2173 constexpr bool operator==( expected
<T1
,E1
> const & x
, expected
<T2
,E2
> const & y
)
2175 return bool(x
) != bool(y
) ? false : bool(x
) ? *x
== *y
: x
.error() == y
.error();
2178 template< typename T1
, typename E1
, typename T2
, typename E2
2180 std::is_void
<T1
>::value
&& std::is_void
<T2
>::value
2183 constexpr bool operator==( expected
<T1
,E1
> const & x
, expected
<T2
,E2
> const & y
)
2185 return bool(x
) != bool(y
) ? false : bool(x
) || static_cast<bool>( x
.error() == y
.error() );
2188 template< typename T1
, typename E1
, typename T2
, typename E2
>
2189 constexpr bool operator!=( expected
<T1
,E1
> const & x
, expected
<T2
,E2
> const & y
)
2194 #if nsel_P0323R <= 2
2196 template< typename T
, typename E
>
2197 constexpr bool operator<( expected
<T
,E
> const & x
, expected
<T
,E
> const & y
)
2199 return (!y
) ? false : (!x
) ? true : *x
< *y
;
2202 template< typename T
, typename E
>
2203 constexpr bool operator>( expected
<T
,E
> const & x
, expected
<T
,E
> const & y
)
2208 template< typename T
, typename E
>
2209 constexpr bool operator<=( expected
<T
,E
> const & x
, expected
<T
,E
> const & y
)
2214 template< typename T
, typename E
>
2215 constexpr bool operator>=( expected
<T
,E
> const & x
, expected
<T
,E
> const & y
)
2222 // x.x.4.7 expected: comparison with T
2224 template< typename T1
, typename E1
, typename T2
2226 !std::is_void
<T1
>::value
2229 constexpr bool operator==( expected
<T1
,E1
> const & x
, T2
const & v
)
2231 return bool(x
) ? *x
== v
: false;
2234 template< typename T1
, typename E1
, typename T2
2236 !std::is_void
<T1
>::value
2239 constexpr bool operator==(T2
const & v
, expected
<T1
,E1
> const & x
)
2241 return bool(x
) ? v
== *x
: false;
2244 template< typename T1
, typename E1
, typename T2
>
2245 constexpr bool operator!=( expected
<T1
,E1
> const & x
, T2
const & v
)
2247 return bool(x
) ? *x
!= v
: true;
2250 template< typename T1
, typename E1
, typename T2
>
2251 constexpr bool operator!=( T2
const & v
, expected
<T1
,E1
> const & x
)
2253 return bool(x
) ? v
!= *x
: true;
2256 #if nsel_P0323R <= 2
2258 template< typename T
, typename E
>
2259 constexpr bool operator<( expected
<T
,E
> const & x
, T
const & v
)
2261 return bool(x
) ? *x
< v
: true;
2264 template< typename T
, typename E
>
2265 constexpr bool operator<( T
const & v
, expected
<T
,E
> const & x
)
2267 return bool(x
) ? v
< *x
: false;
2270 template< typename T
, typename E
>
2271 constexpr bool operator>( T
const & v
, expected
<T
,E
> const & x
)
2273 return bool(x
) ? *x
< v
: false;
2276 template< typename T
, typename E
>
2277 constexpr bool operator>( expected
<T
,E
> const & x
, T
const & v
)
2279 return bool(x
) ? v
< *x
: false;
2282 template< typename T
, typename E
>
2283 constexpr bool operator<=( T
const & v
, expected
<T
,E
> const & x
)
2285 return bool(x
) ? ! ( *x
< v
) : false;
2288 template< typename T
, typename E
>
2289 constexpr bool operator<=( expected
<T
,E
> const & x
, T
const & v
)
2291 return bool(x
) ? ! ( v
< *x
) : true;
2294 template< typename T
, typename E
>
2295 constexpr bool operator>=( expected
<T
,E
> const & x
, T
const & v
)
2297 return bool(x
) ? ! ( *x
< v
) : false;
2300 template< typename T
, typename E
>
2301 constexpr bool operator>=( T
const & v
, expected
<T
,E
> const & x
)
2303 return bool(x
) ? ! ( v
< *x
) : true;
2306 #endif // nsel_P0323R
2308 // x.x.4.8 expected: comparison with unexpected_type
2310 template< typename T1
, typename E1
, typename E2
>
2311 constexpr bool operator==( expected
<T1
,E1
> const & x
, unexpected_type
<E2
> const & u
)
2313 return (!x
) ? x
.get_unexpected() == u
: false;
2316 template< typename T1
, typename E1
, typename E2
>
2317 constexpr bool operator==( unexpected_type
<E2
> const & u
, expected
<T1
,E1
> const & x
)
2322 template< typename T1
, typename E1
, typename E2
>
2323 constexpr bool operator!=( expected
<T1
,E1
> const & x
, unexpected_type
<E2
> const & u
)
2325 return ! ( x
== u
);
2328 template< typename T1
, typename E1
, typename E2
>
2329 constexpr bool operator!=( unexpected_type
<E2
> const & u
, expected
<T1
,E1
> const & x
)
2331 return ! ( x
== u
);
2334 #if nsel_P0323R <= 2
2336 template< typename T
, typename E
>
2337 constexpr bool operator<( expected
<T
,E
> const & x
, unexpected_type
<E
> const & u
)
2339 return (!x
) ? ( x
.get_unexpected() < u
) : false;
2342 template< typename T
, typename E
>
2343 constexpr bool operator<( unexpected_type
<E
> const & u
, expected
<T
,E
> const & x
)
2345 return (!x
) ? ( u
< x
.get_unexpected() ) : true ;
2348 template< typename T
, typename E
>
2349 constexpr bool operator>( expected
<T
,E
> const & x
, unexpected_type
<E
> const & u
)
2354 template< typename T
, typename E
>
2355 constexpr bool operator>( unexpected_type
<E
> const & u
, expected
<T
,E
> const & x
)
2360 template< typename T
, typename E
>
2361 constexpr bool operator<=( expected
<T
,E
> const & x
, unexpected_type
<E
> const & u
)
2366 template< typename T
, typename E
>
2367 constexpr bool operator<=( unexpected_type
<E
> const & u
, expected
<T
,E
> const & x
)
2372 template< typename T
, typename E
>
2373 constexpr bool operator>=( expected
<T
,E
> const & x
, unexpected_type
<E
> const & u
)
2378 template< typename T
, typename E
>
2379 constexpr bool operator>=( unexpected_type
<E
> const & u
, expected
<T
,E
> const & x
)
2384 #endif // nsel_P0323R
2386 /// x.x.x Specialized algorithms
2388 template< typename T
, typename E
2390 ( std::is_void
<T
>::value
|| std::is_move_constructible
<T
>::value
)
2391 && std::is_move_constructible
<E
>::value
2392 && std17::is_swappable
<T
>::value
2393 && std17::is_swappable
<E
>::value
)
2395 void swap( expected
<T
,E
> & x
, expected
<T
,E
> & y
) noexcept ( noexcept ( x
.swap(y
) ) )
2400 #if nsel_P0323R <= 3
2402 template< typename T
>
2403 constexpr auto make_expected( T
&& v
) -> expected
< typename
std::decay
<T
>::type
>
2405 return expected
< typename
std::decay
<T
>::type
>( std::forward
<T
>( v
) );
2408 // expected<void> specialization:
2410 auto inline make_expected() -> expected
<void>
2412 return expected
<void>( in_place
);
2415 template< typename T
>
2416 constexpr auto make_expected_from_current_exception() -> expected
<T
>
2418 return expected
<T
>( make_unexpected_from_current_exception() );
2421 template< typename T
>
2422 auto make_expected_from_exception( std::exception_ptr v
) -> expected
<T
>
2424 return expected
<T
>( unexpected_type
<std::exception_ptr
>( std::forward
<std::exception_ptr
>( v
) ) );
2427 template< typename T
, typename E
>
2428 constexpr auto make_expected_from_error( E e
) -> expected
<T
, typename
std::decay
<E
>::type
>
2430 return expected
<T
, typename
std::decay
<E
>::type
>( make_unexpected( e
) );
2433 template< typename F
2434 nsel_REQUIRES_T( ! std::is_same
<typename
std::result_of
<F()>::type
, void>::value
)
2436 /*nsel_constexpr14*/
2437 auto make_expected_from_call( F f
) -> expected
< typename
std::result_of
<F()>::type
>
2441 return make_expected( f() );
2445 return make_unexpected_from_current_exception();
2449 template< typename F
2450 nsel_REQUIRES_T( std::is_same
<typename
std::result_of
<F()>::type
, void>::value
)
2452 /*nsel_constexpr14*/
2453 auto make_expected_from_call( F f
) -> expected
<void>
2458 return make_expected();
2462 return make_unexpected_from_current_exception();
2466 #endif // nsel_P0323R
2468 } // namespace expected_lite
2470 using namespace expected_lite
;
2472 // using expected_lite::expected;
2475 } // namespace nonstd
2479 // expected: hash support
2481 template< typename T
, typename E
>
2482 struct hash
< nonstd::expected
<T
,E
> >
2484 using result_type
= std::size_t;
2485 using argument_type
= nonstd::expected
<T
,E
>;
2487 constexpr result_type
operator()(argument_type
const & arg
) const
2489 return arg
? std::hash
<T
>{}(*arg
) : result_type
{};
2493 // TBD - ?? remove? see spec.
2494 template< typename T
, typename E
>
2495 struct hash
< nonstd::expected
<T
&,E
> >
2497 using result_type
= std::size_t;
2498 using argument_type
= nonstd::expected
<T
&,E
>;
2500 constexpr result_type
operator()(argument_type
const & arg
) const
2502 return arg
? std::hash
<T
>{}(*arg
) : result_type
{};
2507 // bool(e), hash<expected<void,E>>()(e) shall evaluate to the hashing true;
2508 // otherwise it evaluates to an unspecified value if E is exception_ptr or
2509 // a combination of hashing false and hash<E>()(e.error()).
2511 template< typename E
>
2512 struct hash
< nonstd::expected
<void,E
> >
2520 // void unexpected() is deprecated && removed in C++17
2522 #if nsel_CPP17_OR_GREATER || nsel_COMPILER_MSVC_VERSION > 141
2523 template< typename E
>
2524 using unexpected
= unexpected_type
<E
>;
2527 } // namespace nonstd
2529 #undef nsel_REQUIRES
2530 #undef nsel_REQUIRES_0
2531 #undef nsel_REQUIRES_T
2533 nsel_RESTORE_WARNINGS()
2535 #endif // nsel_USES_STD_EXPECTED
2537 #endif // NONSTD_EXPECTED_LITE_HPP