Sync translations from Transifex and run lupdate
[qBittorrent.git] / src / base / 3rdparty / expected.hpp
bloba1ddc6f0e5f40b676d7eb4f05519a8903c6aed34
1 // This version targets C++11 and later.
2 //
3 // Copyright (C) 2016-2020 Martin Moene.
4 //
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)
7 //
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:
32 #ifdef __has_include
33 # if __has_include(<nonstd/expected.tweak.hpp>)
34 # include <nonstd/expected.tweak.hpp>
35 # endif
36 #define expected_HAVE_TWEAK_HEADER 1
37 #else
38 #define expected_HAVE_TWEAK_HEADER 0
39 //# pragma message("expected.hpp: Note: Tweak header not supported.")
40 #endif
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 )
46 #endif
48 // Proposal revisions:
50 // DXXXXR0: --
51 // N4015 : -2 (2014-05-26)
52 // N4109 : -1 (2014-06-29)
53 // P0323R0: 0 (2016-05-28)
54 // P0323R1: 1 (2016-10-12)
55 // -------:
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
65 #ifndef nsel_P0323R
66 # define nsel_P0323R 7
67 #endif
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
74 # endif
75 # if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || (_HAS_EXCEPTIONS)
76 # define nsel_CONFIG_NO_EXCEPTIONS 0
77 # else
78 # define nsel_CONFIG_NO_EXCEPTIONS 1
79 # endif
80 #endif
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 )
86 #endif
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 )
94 # else
95 # define nsel_CPLUSPLUS __cplusplus
96 # endif
97 #endif
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
111 # else
112 # define nsel_HAVE_STD_EXPECTED 0
113 # endif
114 #else
115 # define nsel_HAVE_STD_EXPECTED 0
116 #endif
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
131 #include <utility>
133 namespace nonstd {
135 using std::in_place;
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
154 #include <cstddef>
156 namespace nonstd {
157 namespace detail {
159 template< class T >
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 {};
169 template< class T >
170 inline in_place_t in_place( detail::in_place_type_tag<T> = detail::in_place_type_tag<T>() )
172 return in_place_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>() )
178 return in_place_t();
181 template< class T >
182 inline in_place_t in_place_type( detail::in_place_type_tag<T> = detail::in_place_type_tag<T>() )
184 return in_place_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>() )
190 return in_place_t();
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
214 #include <expected>
216 namespace nonstd {
218 using std::expected;
219 // ...
222 #else // nsel_USES_STD_EXPECTED
224 #include <cassert>
225 #include <exception>
226 #include <functional>
227 #include <initializer_list>
228 #include <memory>
229 #include <new>
230 #include <system_error>
231 #include <type_traits>
232 #include <utility>
234 // additional includes:
236 #if nsel_CONFIG_NO_EXCEPTIONS
237 # if nsel_CONFIG_NO_EXCEPTIONS_SEH
238 # include <windows.h> // for ExceptionCodes
239 # else
240 // already included: <cassert>
241 # endif
242 #else
243 # include <stdexcept>
244 #endif
246 // C++ feature usage:
248 #if nsel_CPP11_OR_GREATER
249 # define nsel_constexpr constexpr
250 #else
251 # define nsel_constexpr /*constexpr*/
252 #endif
254 #if nsel_CPP14_OR_GREATER
255 # define nsel_constexpr14 constexpr
256 #else
257 # define nsel_constexpr14 /*constexpr*/
258 #endif
260 #if nsel_CPP17_OR_GREATER
261 # define nsel_inline17 inline
262 #else
263 # define nsel_inline17 /*inline*/
264 #endif
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)) )
283 #else
284 # define nsel_COMPILER_MSVC_VER 0
285 # define nsel_COMPILER_MSVC_VERSION 0
286 #endif
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__)
292 #else
293 # define nsel_COMPILER_CLANG_VERSION 0
294 #endif
296 #if defined(__GNUC__) && !defined(__clang__)
297 # define nsel_COMPILER_GNUC_VERSION nsel_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
298 #else
299 # define nsel_COMPILER_GNUC_VERSION 0
300 #endif
302 // half-open range [lo..hi):
303 //#define nsel_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) )
305 // Method enabling
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:
321 #ifdef _HAS_CPP0X
322 # define nsel_HAS_CPP0X _HAS_CPP0X
323 #else
324 # define nsel_HAS_CPP0X 0
325 #endif
327 //#define nsel_CPP11_140 (nsel_CPP11_OR_GREATER || nsel_COMPILER_MSVC_VER >= 1900)
329 // Clang, GNUC, MSVC warning suppression macros:
331 #ifdef __clang__
332 # pragma clang diagnostic push
333 #elif defined __GNUC__
334 # pragma GCC diagnostic push
335 #endif // __clang__
337 #if nsel_COMPILER_MSVC_VERSION >= 140
338 # pragma warning( push )
339 # define nsel_DISABLE_MSVC_WARNINGS(codes) __pragma( warning(disable: codes) )
340 #else
341 # define nsel_DISABLE_MSVC_WARNINGS(codes)
342 #endif
344 #ifdef __clang__
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 ) )
350 #else
351 # define nsel_RESTORE_WARNINGS()
352 #endif
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 )
360 // expected:
363 namespace nonstd { namespace expected_lite {
365 // type traits C++17:
367 namespace std17 {
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
377 namespace detail {
379 using std::swap;
381 struct is_swappable
383 template< typename T, typename = decltype( swap( std::declval<T&>(), std::declval<T&>() ) ) >
384 static std::true_type test( int /* unused */);
386 template< typename >
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>()>{}
403 template< typename >
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) ){};
416 // conjunction:
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
426 } // namespace std17
428 // type traits C++20:
430 namespace std20 {
432 #if defined(__cpp_lib_remove_cvref)
434 using std::remove_cvref;
436 #else
438 template< typename T >
439 struct remove_cvref
441 typedef typename std::remove_cv< typename std::remove_reference<T>::type >::type type;
444 #endif
446 } // namespace std20
448 // forward declaration:
450 template< typename T, typename E >
451 class expected;
453 namespace detail {
455 /// discriminated union to hold value or 'error'.
457 template< typename T, typename E >
458 class storage_t_impl
460 template< typename, typename > friend class nonstd::expected_lite::expected;
462 public:
463 using value_type = T;
464 using error_type = E;
466 // no-op construction
467 storage_t_impl() {}
468 ~storage_t_impl() {}
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 &
530 return m_value;
533 value_type & value() &
535 return m_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
550 return &m_value;
553 value_type * value_ptr()
555 return &m_value;
558 error_type const & error() const &
560 return m_error;
563 error_type & error() &
565 return m_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
580 return m_has_value;
583 void set_has_value( bool v )
585 m_has_value = v;
588 private:
589 union
591 value_type m_value;
592 error_type m_error;
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;
605 public:
606 using value_type = void;
607 using error_type = E;
609 // no-op construction
610 storage_t_impl() {}
611 ~storage_t_impl() {}
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 &
646 return m_error;
649 error_type & error() &
651 return m_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
666 return m_has_value;
669 void set_has_value( bool v )
671 m_has_value = v;
674 private:
675 union
677 char m_dummy;
678 error_type m_error;
681 bool m_has_value = false;
684 template< typename T, typename E, bool isConstructable, bool isMoveable >
685 class storage_t
687 public:
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>
702 public:
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>
728 public:
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>
754 public:
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>
775 public:
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>
796 public:
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>
817 public:
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.
839 #if nsel_P0323R <= 2
840 template< typename E = std::exception_ptr >
841 class unexpected_type
842 #else
843 template< typename E >
844 class unexpected_type
845 #endif // nsel_P0323R
847 public:
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
858 nsel_REQUIRES_T(
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
867 nsel_REQUIRES_T(
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
876 nsel_REQUIRES_T(
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
887 nsel_REQUIRES_T(
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
905 nsel_REQUIRES_T(
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
923 nsel_REQUIRES_T(
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
941 nsel_REQUIRES_T(
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 );
967 return *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 );
974 return *this;
977 // x.x.5.2.3 Observers
979 nsel_constexpr14 E & value() & noexcept
981 return m_error;
984 constexpr E const & value() const & noexcept
986 return m_error;
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 );
1001 #endif
1003 // x.x.5.2.4 Swap
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
1013 using std::swap;
1014 swap( m_error, other.m_error );
1017 // TODO: ??? unexpected_type: in-class friend operator==, !=
1019 private:
1020 error_type m_error;
1023 #if nsel_CPP17_OR_GREATER
1025 /// template deduction guide:
1027 template< typename E >
1028 unexpected_type( E ) -> unexpected_type< E >;
1030 #endif
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
1039 template<>
1040 class unexpected_type< std::exception_ptr >
1042 public:
1043 using error_type = std::exception_ptr;
1045 unexpected_type() = delete;
1047 ~unexpected_type(){}
1049 explicit unexpected_type( std::exception_ptr const & error )
1050 : m_error( 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
1064 return m_error;
1067 std::exception_ptr & value()
1069 return m_error;
1072 private:
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 )
1104 return ( y < x );
1107 template< typename E >
1108 constexpr bool operator<=( unexpected_type<E> const & x, unexpected_type<E> const & y )
1110 return ! ( y < x );
1113 template< typename E >
1114 constexpr bool operator>=( unexpected_type<E> const & x, unexpected_type<E> const & y )
1116 return ! ( x < y );
1119 #endif // nsel_P0323R
1121 /// x.x.5 Specialized algorithms
1123 template< typename E
1124 nsel_REQUIRES_T(
1125 std17::is_swappable<E>::value
1128 void swap( unexpected_type<E> & x, unexpected_type<E> & y) noexcept ( noexcept ( x.swap(y) ) )
1130 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*/ )
1139 return false;
1142 inline constexpr bool operator>( unexpected_type<std::exception_ptr> const & /*x*/, unexpected_type<std::exception_ptr> const & /*y*/ )
1144 return false;
1147 inline constexpr bool operator<=( unexpected_type<std::exception_ptr> const & x, unexpected_type<std::exception_ptr> const & y )
1149 return ( x == y );
1152 inline constexpr bool operator>=( unexpected_type<std::exception_ptr> const & x, unexpected_type<std::exception_ptr> const & y )
1154 return ( x == 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
1199 template <>
1200 class bad_expected_access< void > : public std::exception
1202 public:
1203 explicit bad_expected_access()
1204 : std::exception()
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 >
1215 public:
1216 using error_type = E;
1218 explicit bad_expected_access( error_type error )
1219 : m_error( error )
1222 virtual char const * what() const noexcept override
1224 return "bad_expected_access";
1227 nsel_constexpr14 error_type & error() &
1229 return m_error;
1232 constexpr error_type const & error() const &
1234 return m_error;
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 );
1249 #endif
1251 private:
1252 error_type 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
1269 namespace detail {
1270 inline bool text( char const * /*text*/ ) { return true; }
1273 template< typename Error >
1274 struct error_traits
1276 static void rethrow( Error const & /*e*/ )
1278 #if nsel_CONFIG_NO_EXCEPTIONS_SEH
1279 RaiseException( EXCEPTION_ACCESS_VIOLATION, EXCEPTION_NONCONTINUABLE, 0, NULL );
1280 #else
1281 assert( false && detail::text("throw bad_expected_access<Error>{ e };") );
1282 #endif
1286 template<>
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 );
1293 #else
1294 assert( false && detail::text("throw bad_expected_access<std::exception_ptr>{ e };") );
1295 #endif
1299 template<>
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 );
1306 #else
1307 assert( false && detail::text("throw std::system_error( e );") );
1308 #endif
1312 #else // nsel_CONFIG_NO_EXCEPTIONS
1314 template< typename Error >
1315 struct error_traits
1317 static void rethrow( Error const & e )
1319 throw bad_expected_access<Error>{ e };
1323 template<>
1324 struct error_traits< std::exception_ptr >
1326 static void rethrow( std::exception_ptr const & e )
1328 std::rethrow_exception( e );
1332 template<>
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 {
1351 /// class expected
1353 #if nsel_P0323R <= 2
1354 template< typename T, typename E = std::exception_ptr >
1355 class expected
1356 #else
1357 template< typename T, typename E >
1358 class expected
1359 #endif // nsel_P0323R
1361 private:
1362 template< typename, typename > friend class expected;
1364 public:
1365 using value_type = T;
1366 using error_type = E;
1367 using unexpected_type = nonstd::unexpected_type<E>;
1369 template< typename U >
1370 struct rebind
1372 using type = expected<U, error_type>;
1375 // x.x.4.1 constructors
1377 nsel_REQUIRES_0(
1378 std::is_default_constructible<T>::value
1380 nsel_constexpr14 expected()
1381 : contained( true )
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
1390 nsel_REQUIRES_T(
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
1412 nsel_REQUIRES_T(
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
1434 nsel_REQUIRES_T(
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
1456 nsel_REQUIRES_T(
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
1478 nsel_REQUIRES_T(
1479 std::is_copy_constructible<U>::value
1482 nsel_constexpr14 expected( value_type const & value )
1483 : contained( true )
1485 contained.construct_value( value );
1488 template< typename U = T
1489 nsel_REQUIRES_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
1502 : contained( true )
1504 contained.construct_value( T{ std::forward<U>( value ) } );
1507 template< typename U = T
1508 nsel_REQUIRES_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
1521 : contained( true )
1523 contained.construct_value( std::forward<U>( value ) );
1526 // construct error:
1528 template< typename G = E
1529 nsel_REQUIRES_T(
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
1541 nsel_REQUIRES_T(
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
1553 nsel_REQUIRES_T(
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
1565 nsel_REQUIRES_T(
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
1579 nsel_REQUIRES_T(
1580 std::is_constructible<T, Args&&...>::value
1583 nsel_constexpr14 explicit expected( nonstd_lite_in_place_t(T), Args&&... args )
1584 : contained( true )
1586 contained.emplace_value( std::forward<Args>( args )... );
1589 template< typename U, typename... Args
1590 nsel_REQUIRES_T(
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 )
1595 : contained( true )
1597 contained.emplace_value( il, std::forward<Args>( args )... );
1600 // in-place construction, error
1602 template< typename... Args
1603 nsel_REQUIRES_T(
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
1614 nsel_REQUIRES_T(
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.
1630 ~expected()
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 );
1641 return *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 );
1652 return *this;
1655 template< typename U
1656 nsel_REQUIRES_T(
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 );
1666 return *this;
1669 template< typename G = E
1670 nsel_REQUIRES_T(
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 );
1679 return *this;
1682 template< typename G = E
1683 nsel_REQUIRES_T(
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 );
1692 return *this;
1695 template< typename... Args
1696 nsel_REQUIRES_T(
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 );
1703 return value();
1706 template< typename U, typename... Args
1707 nsel_REQUIRES_T(
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 );
1714 return value();
1717 // x.x.4.4 swap
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
1731 using std::swap;
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() ) );
1782 #endif
1784 constexpr explicit operator bool() const noexcept
1786 return has_value();
1789 constexpr bool has_value() const noexcept
1791 return contained.has_value();
1794 constexpr value_type const & value() const &
1796 return has_value()
1797 ? ( contained.value() )
1798 : ( error_traits<error_type>::rethrow( contained.error() ), contained.value() );
1801 value_type & value() &
1803 return has_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() ) );
1824 #endif
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() ) );
1848 #endif
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
1863 nsel_REQUIRES_T(
1864 std::is_copy_constructible< T>::value
1865 && std::is_convertible<U&&, T>::value
1868 value_type value_or( U && v ) const &
1870 return has_value()
1871 ? contained.value()
1872 : static_cast<T>( std::forward<U>( v ) );
1875 template< typename U
1876 nsel_REQUIRES_T(
1877 std::is_move_constructible< T>::value
1878 && std::is_convertible<U&&, T>::value
1881 value_type value_or( U && v ) &&
1883 return has_value()
1884 ? std::move( contained.value() )
1885 : static_cast<T>( std::forward<U>( v ) );
1888 // unwrap()
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() &&;
1902 // factories
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);
1919 private:
1920 detail::storage_t
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
1927 contained;
1930 /// class expected, void specialization
1932 template< typename E >
1933 class expected<void, E>
1935 private:
1936 template< typename, typename > friend class expected;
1938 public:
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
1946 : contained( true )
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) )
1953 : contained( true )
1956 template< typename G = E
1957 nsel_REQUIRES_T(
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
1968 nsel_REQUIRES_T(
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
1979 nsel_REQUIRES_T(
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
1990 nsel_REQUIRES_T(
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
2001 nsel_REQUIRES_T(
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
2012 nsel_REQUIRES_T(
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 )... );
2022 // destructor
2024 ~expected()
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 );
2037 return *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 );
2046 return *this;
2049 void emplace()
2051 expected().swap( *this );
2054 // x.x.4.4 swap
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
2066 using std::swap;
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
2082 return has_value();
2085 constexpr bool has_value() const noexcept
2087 return contained.has_value();
2090 void value() const
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() ) );
2120 #endif
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() &&;
2138 // factories
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);
2155 private:
2156 detail::storage_t
2158 void
2160 , std::is_copy_constructible<E>::value
2161 , std::is_move_constructible<E>::value
2163 contained;
2166 // x.x.4.6 expected<>: comparison operators
2168 template< typename T1, typename E1, typename T2, typename E2
2169 nsel_REQUIRES_T(
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
2179 nsel_REQUIRES_T(
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 )
2191 return !(x == 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 )
2205 return (y < x);
2208 template< typename T, typename E >
2209 constexpr bool operator<=( expected<T,E> const & x, expected<T,E> const & y )
2211 return !(y < x);
2214 template< typename T, typename E >
2215 constexpr bool operator>=( expected<T,E> const & x, expected<T,E> const & y )
2217 return !(x < y);
2220 #endif
2222 // x.x.4.7 expected: comparison with T
2224 template< typename T1, typename E1, typename T2
2225 nsel_REQUIRES_T(
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
2235 nsel_REQUIRES_T(
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 )
2319 return ( x == u );
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 )
2351 return ( u < x );
2354 template< typename T, typename E >
2355 constexpr bool operator>( unexpected_type<E> const & u, expected<T,E> const & x )
2357 return ( x < u );
2360 template< typename T, typename E >
2361 constexpr bool operator<=( expected<T,E> const & x, unexpected_type<E> const & u )
2363 return ! ( u < x );
2366 template< typename T, typename E >
2367 constexpr bool operator<=( unexpected_type<E> const & u, expected<T,E> const & x)
2369 return ! ( x < u );
2372 template< typename T, typename E >
2373 constexpr bool operator>=( expected<T,E> const & x, unexpected_type<E> const & u )
2375 return ! ( u > x );
2378 template< typename T, typename E >
2379 constexpr bool operator>=( unexpected_type<E> const & u, expected<T,E> const & x )
2381 return ! ( x > u );
2384 #endif // nsel_P0323R
2386 /// x.x.x Specialized algorithms
2388 template< typename T, typename E
2389 nsel_REQUIRES_T(
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) ) )
2397 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() );
2443 catch (...)
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>
2457 f();
2458 return make_expected();
2460 catch (...)
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;
2473 // using ...
2475 } // namespace nonstd
2477 namespace std {
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{};
2506 // TBD - implement
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> >
2516 } // namespace std
2518 namespace nonstd {
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>;
2525 #endif
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