RESTinio
Loading...
Searching...
No Matches
expected.hpp
Go to the documentation of this file.
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
11
12#ifndef NONSTD_EXPECTED_LITE_HPP
13#define NONSTD_EXPECTED_LITE_HPP
14
15#define expected_lite_MAJOR 0
16#define expected_lite_MINOR 6
17#define expected_lite_PATCH 1
18
19#define expected_lite_VERSION expected_STRINGIFY(expected_lite_MAJOR) "." expected_STRINGIFY(expected_lite_MINOR) "." expected_STRINGIFY(expected_lite_PATCH)
20
21#define expected_STRINGIFY( x ) expected_STRINGIFY_( x )
22#define expected_STRINGIFY_( x ) #x
23
24// expected-lite configuration:
25
26#define nsel_EXPECTED_DEFAULT 0
27#define nsel_EXPECTED_NONSTD 1
28#define nsel_EXPECTED_STD 2
29
30// tweak header support:
31
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
41
42// expected selection and configuration:
43
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
47
48// Proposal revisions:
49//
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) *
62//
63// expected-lite uses 2 and higher
64
65#ifndef nsel_P0323R
66# define nsel_P0323R 7
67#endif
68
69// Control presence of C++ exception handling (try and auto discover):
70
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
81
82// at default use SEH with MSVC for no C++ exceptions
83
84#ifndef nsel_CONFIG_NO_EXCEPTIONS_SEH
85# define nsel_CONFIG_NO_EXCEPTIONS_SEH ( nsel_CONFIG_NO_EXCEPTIONS && _MSC_VER )
86#endif
87
88// C++ language version detection (C++20 is speculative):
89// Note: VC14.0/1900 (VS2015) lacks too much from C++14.
90
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
98
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 >= 202000L )
104#define nsel_CPP23_OR_GREATER ( nsel_CPLUSPLUS >= 202300L )
105
106// Use C++23 std::expected if available and requested:
107
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
117
118#define nsel_USES_STD_EXPECTED ( (nsel_CONFIG_SELECT_EXPECTED == nsel_EXPECTED_STD) || ((nsel_CONFIG_SELECT_EXPECTED == nsel_EXPECTED_DEFAULT) && nsel_HAVE_STD_EXPECTED) )
119
120//
121// in_place: code duplicated in any-lite, expected-lite, expected-lite, value-ptr-lite, variant-lite:
122//
123
124#ifndef nonstd_lite_HAVE_IN_PLACE_TYPES
125#define nonstd_lite_HAVE_IN_PLACE_TYPES 1
126
127// C++17 std::in_place in <utility>:
128
129#if nsel_CPP17_OR_GREATER
130
131#include <utility>
132
133namespace nonstd {
134
135using std::in_place;
136using std::in_place_type;
137using std::in_place_index;
138using std::in_place_t;
139using std::in_place_type_t;
140using std::in_place_index_t;
141
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>
145
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>{}
149
150} // namespace nonstd
151
152#else // nsel_CPP17_OR_GREATER
153
154#include <cstddef>
155
156namespace nonstd {
157namespace detail {
158
159template< class T >
161
162template< std::size_t K >
164
165} // namespace detail
166
167struct in_place_t {};
168
169template< class T >
171{
172 return in_place_t();
173}
174
175template< std::size_t K >
177{
178 return in_place_t();
179}
180
181template< class T >
183{
184 return in_place_t();
185}
186
187template< std::size_t K >
189{
190 return in_place_t();
191}
192
193// mimic templated typedef:
194
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> )
198
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>
202
203} // namespace nonstd
204
205#endif // nsel_CPP17_OR_GREATER
206#endif // nonstd_lite_HAVE_IN_PLACE_TYPES
207
208//
209// Using std::expected:
210//
211
212#if nsel_USES_STD_EXPECTED
213
214#include <expected>
215
216namespace nonstd {
217
218 using std::expected;
219// ...
220}
221
222#else // nsel_USES_STD_EXPECTED
223
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>
233
234// additional includes:
235
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
245
246// C++ feature usage:
247
248#if nsel_CPP11_OR_GREATER
249# define nsel_constexpr constexpr
250#else
251# define nsel_constexpr /*constexpr*/
252#endif
253
254#if nsel_CPP14_OR_GREATER
255# define nsel_constexpr14 constexpr
256#else
257# define nsel_constexpr14 /*constexpr*/
258#endif
259
260#if nsel_CPP17_OR_GREATER
261# define nsel_inline17 inline
262#else
263# define nsel_inline17 /*inline*/
264#endif
265
266// Compiler versions:
267//
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)
279
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
287
288#define nsel_COMPILER_VERSION( major, minor, patch ) ( 10 * ( 10 * (major) + (minor) ) + (patch) )
289
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
295
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
301
302// half-open range [lo..hi):
303//#define nsel_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) )
304
305// Method enabling
306
307#define nsel_REQUIRES_0(...) \
308 template< bool B = (__VA_ARGS__), typename std::enable_if<B, int>::type = 0 >
309
310#define nsel_REQUIRES_T(...) \
311 , typename std::enable_if< (__VA_ARGS__), int >::type = 0
312
313#define nsel_REQUIRES_R(R, ...) \
314 typename std::enable_if< (__VA_ARGS__), R>::type
315
316#define nsel_REQUIRES_A(...) \
317 , typename std::enable_if< (__VA_ARGS__), void*>::type = nullptr
318
319// Presence of language and library features:
320
321#ifdef _HAS_CPP0X
322# define nsel_HAS_CPP0X _HAS_CPP0X
323#else
324# define nsel_HAS_CPP0X 0
325#endif
326
327//#define nsel_CPP11_140 (nsel_CPP11_OR_GREATER || nsel_COMPILER_MSVC_VER >= 1900)
328
329// Clang, GNUC, MSVC warning suppression macros:
330
331#ifdef __clang__
332# pragma clang diagnostic push
333#elif defined __GNUC__
334# pragma GCC diagnostic push
335#endif // __clang__
336
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
343
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
353
354// Suppress the following MSVC (GSL) warnings:
355// - C26409: Avoid calling new and delete explicitly, use std::make_unique<T> instead (r.11)
356
358
359//
360// expected:
361//
362
363namespace nonstd { namespace expected_lite {
364
365// type traits C++17:
366
367namespace std17 {
368
369#if nsel_CPP17_OR_GREATER
370
371using std::conjunction;
372using std::is_swappable;
373using std::is_nothrow_swappable;
374
375#else // nsel_CPP17_OR_GREATER
376
377namespace detail {
378
379using std::swap;
380
381struct is_swappable
382{
383 template< typename T, typename = decltype( swap( std::declval<T&>(), std::declval<T&>() ) ) >
384 static std::true_type test( int /* unused */);
385
386 template< typename >
387 static std::false_type test(...);
388};
389
390struct is_nothrow_swappable
391{
392 // wrap noexcept(expr) in separate function as work-around for VC140 (VS2015):
393
394 template< typename T >
395 static constexpr bool satisfies()
396 {
397 return noexcept( swap( std::declval<T&>(), std::declval<T&>() ) );
398 }
399
400 template< typename T >
401 static auto test( int ) -> std::integral_constant<bool, satisfies<T>()>{}
402
403 template< typename >
404 static auto test(...) -> std::false_type;
405};
406} // namespace detail
407
408// is [nothow] swappable:
409
410template< typename T >
411struct is_swappable : decltype( detail::is_swappable::test<T>(0) ){};
412
413template< typename T >
414struct is_nothrow_swappable : decltype( detail::is_nothrow_swappable::test<T>(0) ){};
415
416// conjunction:
417
418template< typename... > struct conjunction : std::true_type{};
419template< typename B1 > struct conjunction<B1> : B1{};
420
421template< typename B1, typename... Bn >
422struct conjunction<B1, Bn...> : std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type{};
423
424#endif // nsel_CPP17_OR_GREATER
425
426} // namespace std17
427
428// type traits C++20:
429
430namespace std20 {
431
432#if defined(__cpp_lib_remove_cvref)
433
434using std::remove_cvref;
435
436#else
437
438template< typename T >
439struct remove_cvref
440{
441 typedef typename std::remove_cv< typename std::remove_reference<T>::type >::type type;
442};
443
444#endif
445
446} // namespace std20
447
448// forward declaration:
449
450template< typename T, typename E >
451class expected;
452
453namespace detail {
454
456
457template< typename T, typename E >
458class storage_t_impl
459{
460 template< typename, typename > friend class nonstd::expected_lite::expected;
461
462public:
463 using value_type = T;
464 using error_type = E;
465
466 // no-op construction
467 storage_t_impl() {}
468 ~storage_t_impl() {}
469
470 explicit storage_t_impl( bool has_value )
471 : m_has_value( has_value )
472 {}
473
474 void construct_value( value_type const & e )
475 {
476 new( &m_value ) value_type( e );
477 }
478
479 void construct_value( value_type && e )
480 {
481 new( &m_value ) value_type( std::move( e ) );
482 }
483
484 template< class... Args >
485 void emplace_value( Args&&... args )
486 {
487 new( &m_value ) value_type( std::forward<Args>(args)...);
488 }
489
490 template< class U, class... Args >
491 void emplace_value( std::initializer_list<U> il, Args&&... args )
492 {
493 new( &m_value ) value_type( il, std::forward<Args>(args)... );
494 }
495
496 void destruct_value()
497 {
498 m_value.~value_type();
499 }
500
501 void construct_error( error_type const & e )
502 {
503 new( &m_error ) error_type( e );
504 }
505
506 void construct_error( error_type && e )
507 {
508 new( &m_error ) error_type( std::move( e ) );
509 }
510
511 template< class... Args >
512 void emplace_error( Args&&... args )
513 {
514 new( &m_error ) error_type( std::forward<Args>(args)...);
515 }
516
517 template< class U, class... Args >
518 void emplace_error( std::initializer_list<U> il, Args&&... args )
519 {
520 new( &m_error ) error_type( il, std::forward<Args>(args)... );
521 }
522
523 void destruct_error()
524 {
525 m_error.~error_type();
526 }
527
528 constexpr value_type const & value() const &
529 {
530 return m_value;
531 }
532
533 value_type & value() &
534 {
535 return m_value;
536 }
537
538 constexpr value_type const && value() const &&
539 {
540 return std::move( m_value );
541 }
542
543 nsel_constexpr14 value_type && value() &&
544 {
545 return std::move( m_value );
546 }
547
548 value_type const * value_ptr() const
549 {
550 return &m_value;
551 }
552
553 value_type * value_ptr()
554 {
555 return &m_value;
556 }
557
558 error_type const & error() const &
559 {
560 return m_error;
561 }
562
563 error_type & error() &
564 {
565 return m_error;
566 }
567
568 constexpr error_type const && error() const &&
569 {
570 return std::move( m_error );
571 }
572
573 nsel_constexpr14 error_type && error() &&
574 {
575 return std::move( m_error );
576 }
577
578 bool has_value() const
579 {
580 return m_has_value;
581 }
582
583 void set_has_value( bool v )
584 {
585 m_has_value = v;
586 }
587
588private:
589 union
590 {
591 value_type m_value;
592 error_type m_error;
593 };
594
595 bool m_has_value = false;
596};
597
599
600template< typename E >
601struct storage_t_impl<void, E>
602{
603 template< typename, typename > friend class nonstd::expected_lite::expected;
604
605public:
606 using value_type = void;
607 using error_type = E;
608
609 // no-op construction
610 storage_t_impl() {}
611 ~storage_t_impl() {}
612
613 explicit storage_t_impl( bool has_value )
614 : m_has_value( has_value )
615 {}
616
617 void construct_error( error_type const & e )
618 {
619 new( &m_error ) error_type( e );
620 }
621
622 void construct_error( error_type && e )
623 {
624 new( &m_error ) error_type( std::move( e ) );
625 }
626
627 template< class... Args >
628 void emplace_error( Args&&... args )
629 {
630 new( &m_error ) error_type( std::forward<Args>(args)...);
631 }
632
633 template< class U, class... Args >
634 void emplace_error( std::initializer_list<U> il, Args&&... args )
635 {
636 new( &m_error ) error_type( il, std::forward<Args>(args)... );
637 }
638
639 void destruct_error()
640 {
641 m_error.~error_type();
642 }
643
644 error_type const & error() const &
645 {
646 return m_error;
647 }
648
649 error_type & error() &
650 {
651 return m_error;
652 }
653
654 constexpr error_type const && error() const &&
655 {
656 return std::move( m_error );
657 }
658
659 nsel_constexpr14 error_type && error() &&
660 {
661 return std::move( m_error );
662 }
663
664 bool has_value() const
665 {
666 return m_has_value;
667 }
668
669 void set_has_value( bool v )
670 {
671 m_has_value = v;
672 }
673
674private:
675 union
676 {
677 char m_dummy;
678 error_type m_error;
679 };
680
681 bool m_has_value = false;
682};
683
684template< typename T, typename E, bool isConstructable, bool isMoveable >
685class storage_t
686{
687public:
688 storage_t() = default;
689 ~storage_t() = default;
690
691 explicit storage_t( bool has_value )
692 : storage_t_impl<T, E>( has_value )
693 {}
694
695 storage_t( storage_t const & other ) = delete;
696 storage_t( storage_t && other ) = delete;
697};
698
699template< typename T, typename E >
700class storage_t<T, E, true, true> : public storage_t_impl<T, E>
701{
702public:
703 storage_t() = default;
704 ~storage_t() = default;
705
706 explicit storage_t( bool has_value )
707 : storage_t_impl<T, E>( has_value )
708 {}
709
710 storage_t( storage_t const & other )
711 : storage_t_impl<T, E>( other.has_value() )
712 {
713 if ( this->has_value() ) this->construct_value( other.value() );
714 else this->construct_error( other.error() );
715 }
716
717 storage_t(storage_t && other )
718 : storage_t_impl<T, E>( other.has_value() )
719 {
720 if ( this->has_value() ) this->construct_value( std::move( other.value() ) );
721 else this->construct_error( std::move( other.error() ) );
722 }
723};
724
725template< typename E >
726class storage_t<void, E, true, true> : public storage_t_impl<void, E>
727{
728public:
729 storage_t() = default;
730 ~storage_t() = default;
731
732 explicit storage_t( bool has_value )
733 : storage_t_impl<void, E>( has_value )
734 {}
735
736 storage_t( storage_t const & other )
737 : storage_t_impl<void, E>( other.has_value() )
738 {
739 if ( this->has_value() ) ;
740 else this->construct_error( other.error() );
741 }
742
743 storage_t(storage_t && other )
744 : storage_t_impl<void, E>( other.has_value() )
745 {
746 if ( this->has_value() ) ;
747 else this->construct_error( std::move( other.error() ) );
748 }
749};
750
751template< typename T, typename E >
752class storage_t<T, E, true, false> : public storage_t_impl<T, E>
753{
754public:
755 storage_t() = default;
756 ~storage_t() = default;
757
758 explicit storage_t( bool has_value )
759 : storage_t_impl<T, E>( has_value )
760 {}
761
762 storage_t( storage_t const & other )
763 : storage_t_impl<T, E>(other.has_value())
764 {
765 if ( this->has_value() ) this->construct_value( other.value() );
766 else this->construct_error( other.error() );
767 }
768
769 storage_t( storage_t && other ) = delete;
770};
771
772template< typename E >
773class storage_t<void, E, true, false> : public storage_t_impl<void, E>
774{
775public:
776 storage_t() = default;
777 ~storage_t() = default;
778
779 explicit storage_t( bool has_value )
780 : storage_t_impl<void, E>( has_value )
781 {}
782
783 storage_t( storage_t const & other )
784 : storage_t_impl<void, E>(other.has_value())
785 {
786 if ( this->has_value() ) ;
787 else this->construct_error( other.error() );
788 }
789
790 storage_t( storage_t && other ) = delete;
791};
792
793template< typename T, typename E >
794class storage_t<T, E, false, true> : public storage_t_impl<T, E>
795{
796public:
797 storage_t() = default;
798 ~storage_t() = default;
799
800 explicit storage_t( bool has_value )
801 : storage_t_impl<T, E>( has_value )
802 {}
803
804 storage_t( storage_t const & other ) = delete;
805
806 storage_t( storage_t && other )
807 : storage_t_impl<T, E>( other.has_value() )
808 {
809 if ( this->has_value() ) this->construct_value( std::move( other.value() ) );
810 else this->construct_error( std::move( other.error() ) );
811 }
812};
813
814template< typename E >
815class storage_t<void, E, false, true> : public storage_t_impl<void, E>
816{
817public:
818 storage_t() = default;
819 ~storage_t() = default;
820
821 explicit storage_t( bool has_value )
822 : storage_t_impl<void, E>( has_value )
823 {}
824
825 storage_t( storage_t const & other ) = delete;
826
827 storage_t( storage_t && other )
828 : storage_t_impl<void, E>( other.has_value() )
829 {
830 if ( this->has_value() ) ;
831 else this->construct_error( std::move( other.error() ) );
832 }
833};
834
835} // namespace detail
836
838
839#if nsel_P0323R <= 2
840template< typename E = std::exception_ptr >
841class unexpected_type
842#else
843template< typename E >
844class unexpected_type
845#endif // nsel_P0323R
846{
847public:
848 using error_type = E;
849
850 // x.x.5.2.1 Constructors
851
852// unexpected_type() = delete;
853
854 constexpr unexpected_type( unexpected_type const & ) = default;
855 constexpr unexpected_type( unexpected_type && ) = default;
856
857 template< typename... Args
859 std::is_constructible<E, Args&&...>::value
860 )
861 >
862 constexpr explicit unexpected_type( nonstd_lite_in_place_t(E), Args &&... args )
863 : m_error( std::forward<Args>( args )...)
864 {}
865
866 template< typename U, typename... Args
868 std::is_constructible<E, std::initializer_list<U>, Args&&...>::value
869 )
870 >
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 )...)
873 {}
874
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
880 )
881 >
882 constexpr explicit unexpected_type( E2 && error )
883 : m_error( std::forward<E2>( error ) )
884 {}
885
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 */
898 )
899 >
900 constexpr explicit unexpected_type( unexpected_type<E2> const & error )
901 : m_error( E{ error.value() } )
902 {}
903
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 */
916 )
917 >
918 constexpr /*non-explicit*/ unexpected_type( unexpected_type<E2> const & error )
919 : m_error( error.value() )
920 {}
921
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 */
934 )
935 >
936 constexpr explicit unexpected_type( unexpected_type<E2> && error )
937 : m_error( E{ std::move( error.value() ) } )
938 {}
939
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 */
952 )
953 >
954 constexpr /*non-explicit*/ unexpected_type( unexpected_type<E2> && error )
955 : m_error( std::move( error.value() ) )
956 {}
957
958 // x.x.5.2.2 Assignment
959
960 nsel_constexpr14 unexpected_type& operator=( unexpected_type const & ) = default;
961 nsel_constexpr14 unexpected_type& operator=( unexpected_type && ) = default;
962
963 template< typename E2 = E >
964 nsel_constexpr14 unexpected_type & operator=( unexpected_type<E2> const & other )
965 {
966 unexpected_type{ other.value() }.swap( *this );
967 return *this;
968 }
969
970 template< typename E2 = E >
971 nsel_constexpr14 unexpected_type & operator=( unexpected_type<E2> && other )
972 {
973 unexpected_type{ std::move( other.value() ) }.swap( *this );
974 return *this;
975 }
976
977 // x.x.5.2.3 Observers
978
979 nsel_constexpr14 E & value() & noexcept
980 {
981 return m_error;
982 }
983
984 constexpr E const & value() const & noexcept
985 {
986 return m_error;
987 }
988
989#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490
990
991 nsel_constexpr14 E && value() && noexcept
992 {
993 return std::move( m_error );
994 }
995
996 constexpr E const && value() const && noexcept
997 {
998 return std::move( m_error );
999 }
1000
1001#endif
1002
1003 // x.x.5.2.4 Swap
1004
1005 nsel_REQUIRES_R( void,
1006 std17::is_swappable<E>::value
1007 )
1008 swap( unexpected_type & other ) noexcept (
1009 std17::is_nothrow_swappable<E>::value
1010 )
1011 {
1012 using std::swap;
1013 swap( m_error, other.m_error );
1014 }
1015
1016 // TODO: ??? unexpected_type: in-class friend operator==, !=
1017
1018private:
1019 error_type m_error;
1020};
1021
1022#if nsel_CPP17_OR_GREATER
1023
1025
1026template< typename E >
1027unexpected_type( E ) -> unexpected_type< E >;
1028
1029#endif
1030
1032
1033#if !nsel_CONFIG_NO_EXCEPTIONS
1034#if nsel_P0323R <= 2
1035
1036// TODO: Should expected be specialized for particular E types such as exception_ptr and how?
1037// See p0323r7 2.1. Ergonomics, http://wg21.link/p0323
1038template<>
1039class unexpected_type< std::exception_ptr >
1040{
1041public:
1042 using error_type = std::exception_ptr;
1043
1044 unexpected_type() = delete;
1045
1046 ~unexpected_type(){}
1047
1048 explicit unexpected_type( std::exception_ptr const & error )
1049 : m_error( error )
1050 {}
1051
1052 explicit unexpected_type(std::exception_ptr && error )
1053 : m_error( std::move( error ) )
1054 {}
1055
1056 template< typename E >
1057 explicit unexpected_type( E error )
1058 : m_error( std::make_exception_ptr( error ) )
1059 {}
1060
1061 std::exception_ptr const & value() const
1062 {
1063 return m_error;
1064 }
1065
1066 std::exception_ptr & value()
1067 {
1068 return m_error;
1069 }
1070
1071private:
1072 std::exception_ptr m_error;
1073};
1074
1075#endif // nsel_P0323R
1076#endif // !nsel_CONFIG_NO_EXCEPTIONS
1077
1079
1080template< typename E1, typename E2 >
1081constexpr bool operator==( unexpected_type<E1> const & x, unexpected_type<E2> const & y )
1082{
1083 return x.value() == y.value();
1084}
1085
1086template< typename E1, typename E2 >
1087constexpr bool operator!=( unexpected_type<E1> const & x, unexpected_type<E2> const & y )
1088{
1089 return ! ( x == y );
1090}
1091
1092#if nsel_P0323R <= 2
1093
1094template< typename E >
1095constexpr bool operator<( unexpected_type<E> const & x, unexpected_type<E> const & y )
1096{
1097 return x.value() < y.value();
1098}
1099
1100template< typename E >
1101constexpr bool operator>( unexpected_type<E> const & x, unexpected_type<E> const & y )
1102{
1103 return ( y < x );
1104}
1105
1106template< typename E >
1107constexpr bool operator<=( unexpected_type<E> const & x, unexpected_type<E> const & y )
1108{
1109 return ! ( y < x );
1110}
1111
1112template< typename E >
1113constexpr bool operator>=( unexpected_type<E> const & x, unexpected_type<E> const & y )
1114{
1115 return ! ( x < y );
1116}
1117
1118#endif // nsel_P0323R
1119
1121
1122template< typename E
1124 std17::is_swappable<E>::value
1125 )
1126>
1127void swap( unexpected_type<E> & x, unexpected_type<E> & y) noexcept ( noexcept ( x.swap(y) ) )
1128{
1129 x.swap( y );
1130}
1131
1132#if nsel_P0323R <= 2
1133
1134// unexpected: relational operators for std::exception_ptr:
1135
1136inline constexpr bool operator<( unexpected_type<std::exception_ptr> const & /*x*/, unexpected_type<std::exception_ptr> const & /*y*/ )
1137{
1138 return false;
1139}
1140
1141inline constexpr bool operator>( unexpected_type<std::exception_ptr> const & /*x*/, unexpected_type<std::exception_ptr> const & /*y*/ )
1142{
1143 return false;
1144}
1145
1146inline constexpr bool operator<=( unexpected_type<std::exception_ptr> const & x, unexpected_type<std::exception_ptr> const & y )
1147{
1148 return ( x == y );
1149}
1150
1151inline constexpr bool operator>=( unexpected_type<std::exception_ptr> const & x, unexpected_type<std::exception_ptr> const & y )
1152{
1153 return ( x == y );
1154}
1155
1156#endif // nsel_P0323R
1157
1158// unexpected: traits
1159
1160#if nsel_P0323R <= 3
1161
1162template< typename E>
1163struct is_unexpected : std::false_type {};
1164
1165template< typename E>
1166struct is_unexpected< unexpected_type<E> > : std::true_type {};
1167
1168#endif // nsel_P0323R
1169
1170// unexpected: factory
1171
1172// keep make_unexpected() removed in p0323r2 for pre-C++17:
1173
1174template< typename E>
1176make_unexpected( E && value ) -> unexpected_type< typename std::decay<E>::type >
1177{
1178 return unexpected_type< typename std::decay<E>::type >( std::forward<E>(value) );
1179}
1180
1181#if nsel_P0323R <= 3
1182
1183/*nsel_constexpr14*/ auto inline
1184make_unexpected_from_current_exception() -> unexpected_type< std::exception_ptr >
1185{
1186 return unexpected_type< std::exception_ptr >( std::current_exception() );
1187}
1188
1189#endif // nsel_P0323R
1190
1192
1193template< typename E >
1194class bad_expected_access;
1195
1197
1198template <>
1199class bad_expected_access< void > : public std::exception
1200{
1201public:
1202 explicit bad_expected_access()
1203 : std::exception()
1204 {}
1205};
1206
1208
1209#if !nsel_CONFIG_NO_EXCEPTIONS
1210
1211template< typename E >
1212class bad_expected_access : public bad_expected_access< void >
1213{
1214public:
1215 using error_type = E;
1216
1217 explicit bad_expected_access( error_type error )
1218 : m_error( error )
1219 {}
1220
1221 virtual char const * what() const noexcept override
1222 {
1223 return "bad_expected_access";
1224 }
1225
1226 nsel_constexpr14 error_type & error() &
1227 {
1228 return m_error;
1229 }
1230
1231 constexpr error_type const & error() const &
1232 {
1233 return m_error;
1234 }
1235
1236#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490
1237
1238 nsel_constexpr14 error_type && error() &&
1239 {
1240 return std::move( m_error );
1241 }
1242
1243 constexpr error_type const && error() const &&
1244 {
1245 return std::move( m_error );
1246 }
1247
1248#endif
1249
1250private:
1251 error_type m_error;
1252};
1253
1254#endif // nsel_CONFIG_NO_EXCEPTIONS
1255
1257
1258struct unexpect_t{};
1259using in_place_unexpected_t = unexpect_t;
1260
1261nsel_inline17 constexpr unexpect_t unexpect{};
1262nsel_inline17 constexpr unexpect_t in_place_unexpected{};
1263
1265
1266#if nsel_CONFIG_NO_EXCEPTIONS
1267
1268namespace detail {
1269 inline bool text( char const * /*text*/ ) { return true; }
1270}
1271
1272template< typename Error >
1273struct error_traits
1274{
1275 static void rethrow( Error const & /*e*/ )
1276 {
1277#if nsel_CONFIG_NO_EXCEPTIONS_SEH
1278 RaiseException( EXCEPTION_ACCESS_VIOLATION, EXCEPTION_NONCONTINUABLE, 0, NULL );
1279#else
1280 assert( false && detail::text("throw bad_expected_access<Error>{ e };") );
1281#endif
1282 }
1283};
1284
1285template<>
1286struct error_traits< std::exception_ptr >
1287{
1288 static void rethrow( std::exception_ptr const & /*e*/ )
1289 {
1290#if nsel_CONFIG_NO_EXCEPTIONS_SEH
1291 RaiseException( EXCEPTION_ACCESS_VIOLATION, EXCEPTION_NONCONTINUABLE, 0, NULL );
1292#else
1293 assert( false && detail::text("throw bad_expected_access<std::exception_ptr>{ e };") );
1294#endif
1295 }
1296};
1297
1298template<>
1299struct error_traits< std::error_code >
1300{
1301 static void rethrow( std::error_code const & /*e*/ )
1302 {
1303#if nsel_CONFIG_NO_EXCEPTIONS_SEH
1304 RaiseException( EXCEPTION_ACCESS_VIOLATION, EXCEPTION_NONCONTINUABLE, 0, NULL );
1305#else
1306 assert( false && detail::text("throw std::system_error( e );") );
1307#endif
1308 }
1309};
1310
1311#else // nsel_CONFIG_NO_EXCEPTIONS
1312
1313template< typename Error >
1314struct error_traits
1315{
1316 static void rethrow( Error const & e )
1317 {
1318 throw bad_expected_access<Error>{ e };
1319 }
1320};
1321
1322template<>
1323struct error_traits< std::exception_ptr >
1324{
1325 static void rethrow( std::exception_ptr const & e )
1326 {
1327 std::rethrow_exception( e );
1328 }
1329};
1330
1331template<>
1332struct error_traits< std::error_code >
1333{
1334 static void rethrow( std::error_code const & e )
1335 {
1336 throw std::system_error( e );
1337 }
1338};
1339
1340#endif // nsel_CONFIG_NO_EXCEPTIONS
1341
1342} // namespace expected_lite
1343
1344// provide nonstd::unexpected_type:
1345
1346using expected_lite::unexpected_type;
1347
1348namespace expected_lite {
1349
1351
1352#if nsel_P0323R <= 2
1353template< typename T, typename E = std::exception_ptr >
1354class expected
1355#else
1356template< typename T, typename E >
1357class expected
1358#endif // nsel_P0323R
1359{
1360private:
1361 template< typename, typename > friend class expected;
1362
1363public:
1364 using value_type = T;
1365 using error_type = E;
1366 using unexpected_type = nonstd::unexpected_type<E>;
1367
1368 template< typename U >
1369 struct rebind
1370 {
1371 using type = expected<U, error_type>;
1372 };
1373
1374 // x.x.4.1 constructors
1375
1377 std::is_default_constructible<T>::value
1378 )
1379 nsel_constexpr14 expected()
1380 : contained( true )
1381 {
1382 contained.construct_value( value_type() );
1383 }
1384
1385 nsel_constexpr14 expected( expected const & ) = default;
1386 nsel_constexpr14 expected( expected && ) = default;
1387
1388 template< typename U, typename G
1390 std::is_constructible< T, U const &>::value
1391 && std::is_constructible<E, G const &>::value
1392 && !std::is_constructible<T, expected<U, G> & >::value
1393 && !std::is_constructible<T, expected<U, G> && >::value
1394 && !std::is_constructible<T, expected<U, G> const & >::value
1395 && !std::is_constructible<T, expected<U, G> const && >::value
1396 && !std::is_convertible< expected<U, G> & , T>::value
1397 && !std::is_convertible< expected<U, G> &&, T>::value
1398 && !std::is_convertible< expected<U, G> const & , T>::value
1399 && !std::is_convertible< expected<U, G> const &&, T>::value
1400 && (!std::is_convertible<U const &, T>::value || !std::is_convertible<G const &, E>::value ) /*=> explicit */
1401 )
1402 >
1403 nsel_constexpr14 explicit expected( expected<U, G> const & other )
1404 : contained( other.has_value() )
1405 {
1406 if ( has_value() ) contained.construct_value( T{ other.contained.value() } );
1407 else contained.construct_error( E{ other.contained.error() } );
1408 }
1409
1410 template< typename U, typename G
1412 std::is_constructible< T, U const &>::value
1413 && std::is_constructible<E, G const &>::value
1414 && !std::is_constructible<T, expected<U, G> & >::value
1415 && !std::is_constructible<T, expected<U, G> && >::value
1416 && !std::is_constructible<T, expected<U, G> const & >::value
1417 && !std::is_constructible<T, expected<U, G> const && >::value
1418 && !std::is_convertible< expected<U, G> & , T>::value
1419 && !std::is_convertible< expected<U, G> &&, T>::value
1420 && !std::is_convertible< expected<U, G> const &, T>::value
1421 && !std::is_convertible< expected<U, G> const &&, T>::value
1422 && !(!std::is_convertible<U const &, T>::value || !std::is_convertible<G const &, E>::value ) /*=> non-explicit */
1423 )
1424 >
1425 nsel_constexpr14 /*non-explicit*/ expected( expected<U, G> const & other )
1426 : contained( other.has_value() )
1427 {
1428 if ( has_value() ) contained.construct_value( other.contained.value() );
1429 else contained.construct_error( other.contained.error() );
1430 }
1431
1432 template< typename U, typename G
1434 std::is_constructible< T, U>::value
1435 && std::is_constructible<E, G>::value
1436 && !std::is_constructible<T, expected<U, G> & >::value
1437 && !std::is_constructible<T, expected<U, G> && >::value
1438 && !std::is_constructible<T, expected<U, G> const & >::value
1439 && !std::is_constructible<T, expected<U, G> const && >::value
1440 && !std::is_convertible< expected<U, G> & , T>::value
1441 && !std::is_convertible< expected<U, G> &&, T>::value
1442 && !std::is_convertible< expected<U, G> const & , T>::value
1443 && !std::is_convertible< expected<U, G> const &&, T>::value
1444 && (!std::is_convertible<U, T>::value || !std::is_convertible<G, E>::value ) /*=> explicit */
1445 )
1446 >
1447 nsel_constexpr14 explicit expected( expected<U, G> && other )
1448 : contained( other.has_value() )
1449 {
1450 if ( has_value() ) contained.construct_value( T{ std::move( other.contained.value() ) } );
1451 else contained.construct_error( E{ std::move( other.contained.error() ) } );
1452 }
1453
1454 template< typename U, typename G
1456 std::is_constructible< T, U>::value
1457 && std::is_constructible<E, G>::value
1458 && !std::is_constructible<T, expected<U, G> & >::value
1459 && !std::is_constructible<T, expected<U, G> && >::value
1460 && !std::is_constructible<T, expected<U, G> const & >::value
1461 && !std::is_constructible<T, expected<U, G> const && >::value
1462 && !std::is_convertible< expected<U, G> & , T>::value
1463 && !std::is_convertible< expected<U, G> &&, T>::value
1464 && !std::is_convertible< expected<U, G> const & , T>::value
1465 && !std::is_convertible< expected<U, G> const &&, T>::value
1466 && !(!std::is_convertible<U, T>::value || !std::is_convertible<G, E>::value ) /*=> non-explicit */
1467 )
1468 >
1469 nsel_constexpr14 /*non-explicit*/ expected( expected<U, G> && other )
1470 : contained( other.has_value() )
1471 {
1472 if ( has_value() ) contained.construct_value( std::move( other.contained.value() ) );
1473 else contained.construct_error( std::move( other.contained.error() ) );
1474 }
1475
1476 template< typename U = T
1478 std::is_copy_constructible<U>::value
1479 )
1480 >
1481 nsel_constexpr14 expected( value_type const & value )
1482 : contained( true )
1483 {
1484 contained.construct_value( value );
1485 }
1486
1487 template< typename U = T
1489 std::is_constructible<T,U&&>::value
1490 && !std::is_same<typename std20::remove_cvref<U>::type, nonstd_lite_in_place_t(U)>::value
1491 && !std::is_same< expected<T,E> , typename std20::remove_cvref<U>::type>::value
1492 && !std::is_same<nonstd::unexpected_type<E>, typename std20::remove_cvref<U>::type>::value
1493 && !std::is_convertible<U&&,T>::value /*=> explicit */
1494 )
1495 >
1496 nsel_constexpr14 explicit expected( U && value ) noexcept
1497 (
1498 std::is_nothrow_move_constructible<U>::value &&
1499 std::is_nothrow_move_constructible<E>::value
1500 )
1501 : contained( true )
1502 {
1503 contained.construct_value( T{ std::forward<U>( value ) } );
1504 }
1505
1506 template< typename U = T
1508 std::is_constructible<T,U&&>::value
1509 && !std::is_same<typename std20::remove_cvref<U>::type, nonstd_lite_in_place_t(U)>::value
1510 && !std::is_same< expected<T,E> , typename std20::remove_cvref<U>::type>::value
1511 && !std::is_same<nonstd::unexpected_type<E>, typename std20::remove_cvref<U>::type>::value
1512 && std::is_convertible<U&&,T>::value /*=> non-explicit */
1513 )
1514 >
1515 nsel_constexpr14 /*non-explicit*/ expected( U && value ) noexcept
1516 (
1517 std::is_nothrow_move_constructible<U>::value &&
1518 std::is_nothrow_move_constructible<E>::value
1519 )
1520 : contained( true )
1521 {
1522 contained.construct_value( std::forward<U>( value ) );
1523 }
1524
1525 // construct error:
1526
1527 template< typename G = E
1529 std::is_constructible<E, G const & >::value
1530 && !std::is_convertible< G const &, E>::value /*=> explicit */
1531 )
1532 >
1533 nsel_constexpr14 explicit expected( nonstd::unexpected_type<G> const & error )
1534 : contained( false )
1535 {
1536 contained.construct_error( E{ error.value() } );
1537 }
1538
1539 template< typename G = E
1541 std::is_constructible<E, G const & >::value
1542 && std::is_convertible< G const &, E>::value /*=> non-explicit */
1543 )
1544 >
1545 nsel_constexpr14 /*non-explicit*/ expected( nonstd::unexpected_type<G> const & error )
1546 : contained( false )
1547 {
1548 contained.construct_error( error.value() );
1549 }
1550
1551 template< typename G = E
1553 std::is_constructible<E, G&& >::value
1554 && !std::is_convertible< G&&, E>::value /*=> explicit */
1555 )
1556 >
1557 nsel_constexpr14 explicit expected( nonstd::unexpected_type<G> && error )
1558 : contained( false )
1559 {
1560 contained.construct_error( E{ std::move( error.value() ) } );
1561 }
1562
1563 template< typename G = E
1565 std::is_constructible<E, G&& >::value
1566 && std::is_convertible< G&&, E>::value /*=> non-explicit */
1567 )
1568 >
1569 nsel_constexpr14 /*non-explicit*/ expected( nonstd::unexpected_type<G> && error )
1570 : contained( false )
1571 {
1572 contained.construct_error( std::move( error.value() ) );
1573 }
1574
1575 // in-place construction, value
1576
1577 template< typename... Args
1579 std::is_constructible<T, Args&&...>::value
1580 )
1581 >
1582 nsel_constexpr14 explicit expected( nonstd_lite_in_place_t(T), Args&&... args )
1583 : contained( true )
1584 {
1585 contained.emplace_value( std::forward<Args>( args )... );
1586 }
1587
1588 template< typename U, typename... Args
1590 std::is_constructible<T, std::initializer_list<U>, Args&&...>::value
1591 )
1592 >
1593 nsel_constexpr14 explicit expected( nonstd_lite_in_place_t(T), std::initializer_list<U> il, Args&&... args )
1594 : contained( true )
1595 {
1596 contained.emplace_value( il, std::forward<Args>( args )... );
1597 }
1598
1599 // in-place construction, error
1600
1601 template< typename... Args
1603 std::is_constructible<E, Args&&...>::value
1604 )
1605 >
1606 nsel_constexpr14 explicit expected( unexpect_t, Args&&... args )
1607 : contained( false )
1608 {
1609 contained.emplace_error( std::forward<Args>( args )... );
1610 }
1611
1612 template< typename U, typename... Args
1614 std::is_constructible<E, std::initializer_list<U>, Args&&...>::value
1615 )
1616 >
1617 nsel_constexpr14 explicit expected( unexpect_t, std::initializer_list<U> il, Args&&... args )
1618 : contained( false )
1619 {
1620 contained.emplace_error( il, std::forward<Args>( args )... );
1621 }
1622
1623 // x.x.4.2 destructor
1624
1625 // TODO: ~expected: triviality
1626 // 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>().
1627 // 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.
1628
1629 ~expected()
1630 {
1631 if ( has_value() ) contained.destruct_value();
1632 else contained.destruct_error();
1633 }
1634
1635 // x.x.4.3 assignment
1636
1637 expected & operator=( expected const & other )
1638 {
1639 expected( other ).swap( *this );
1640 return *this;
1641 }
1642
1643 expected & operator=( expected && other ) noexcept
1644 (
1645 std::is_nothrow_move_constructible< T>::value
1646 && std::is_nothrow_move_assignable< T>::value
1647 && std::is_nothrow_move_constructible<E>::value // added for missing
1648 && std::is_nothrow_move_assignable< E>::value ) // nothrow above
1649 {
1650 expected( std::move( other ) ).swap( *this );
1651 return *this;
1652 }
1653
1654 template< typename U
1656 !std::is_same<expected<T,E>, typename std20::remove_cvref<U>::type>::value
1657 && std17::conjunction<std::is_scalar<T>, std::is_same<T, std::decay<U>> >::value
1658 && std::is_constructible<T ,U>::value
1659 && std::is_assignable< T&,U>::value
1660 && std::is_nothrow_move_constructible<E>::value )
1661 >
1662 expected & operator=( U && value )
1663 {
1664 expected( std::forward<U>( value ) ).swap( *this );
1665 return *this;
1666 }
1667
1668 template< typename G = E
1670 std::is_constructible<E, G const&>::value &&
1671 std::is_copy_constructible<G>::value // TODO: std::is_nothrow_copy_constructible<G>
1672 && std::is_copy_assignable<G>::value
1673 )
1674 >
1675 expected & operator=( nonstd::unexpected_type<G> const & error )
1676 {
1677 expected( unexpect, error.value() ).swap( *this );
1678 return *this;
1679 }
1680
1681 template< typename G = E
1683 std::is_constructible<E, G&&>::value &&
1684 std::is_move_constructible<G>::value // TODO: std::is_nothrow_move_constructible<G>
1685 && std::is_move_assignable<G>::value
1686 )
1687 >
1688 expected & operator=( nonstd::unexpected_type<G> && error )
1689 {
1690 expected( unexpect, std::move( error.value() ) ).swap( *this );
1691 return *this;
1692 }
1693
1694 template< typename... Args
1696 std::is_nothrow_constructible<T, Args&&...>::value
1697 )
1698 >
1699 value_type & emplace( Args &&... args )
1700 {
1701 expected( nonstd_lite_in_place(T), std::forward<Args>(args)... ).swap( *this );
1702 return value();
1703 }
1704
1705 template< typename U, typename... Args
1707 std::is_nothrow_constructible<T, std::initializer_list<U>&, Args&&...>::value
1708 )
1709 >
1710 value_type & emplace( std::initializer_list<U> il, Args &&... args )
1711 {
1712 expected( nonstd_lite_in_place(T), il, std::forward<Args>(args)... ).swap( *this );
1713 return value();
1714 }
1715
1716 // x.x.4.4 swap
1717
1718 template< typename U=T, typename G=E >
1719 nsel_REQUIRES_R( void,
1720 std17::is_swappable< U>::value
1721 && std17::is_swappable<G>::value
1722 && ( std::is_move_constructible<U>::value || std::is_move_constructible<G>::value )
1723 )
1724 swap( expected & other ) noexcept
1725 (
1726 std::is_nothrow_move_constructible<T>::value && std17::is_nothrow_swappable<T&>::value &&
1727 std::is_nothrow_move_constructible<E>::value && std17::is_nothrow_swappable<E&>::value
1728 )
1729 {
1730 using std::swap;
1731
1732 if ( bool(*this) && bool(other) ) { swap( contained.value(), other.contained.value() ); }
1733 else if ( ! bool(*this) && ! bool(other) ) { swap( contained.error(), other.contained.error() ); }
1734 else if ( bool(*this) && ! bool(other) ) { error_type t( std::move( other.error() ) );
1735 other.contained.destruct_error();
1736 other.contained.construct_value( std::move( contained.value() ) );
1737 contained.destruct_value();
1738 contained.construct_error( std::move( t ) );
1739 bool has_value = contained.has_value();
1740 bool other_has_value = other.has_value();
1741 other.contained.set_has_value(has_value);
1742 contained.set_has_value(other_has_value);
1743 }
1744 else if ( ! bool(*this) && bool(other) ) { other.swap( *this ); }
1745 }
1746
1747 // x.x.4.5 observers
1748
1749 constexpr value_type const * operator ->() const
1750 {
1751 return assert( has_value() ), contained.value_ptr();
1752 }
1753
1754 value_type * operator ->()
1755 {
1756 return assert( has_value() ), contained.value_ptr();
1757 }
1758
1759 constexpr value_type const & operator *() const &
1760 {
1761 return assert( has_value() ), contained.value();
1762 }
1763
1764 value_type & operator *() &
1765 {
1766 return assert( has_value() ), contained.value();
1767 }
1768
1769#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490
1770
1771 constexpr value_type const && operator *() const &&
1772 {
1773 return std::move( ( assert( has_value() ), contained.value() ) );
1774 }
1775
1776 nsel_constexpr14 value_type && operator *() &&
1777 {
1778 return std::move( ( assert( has_value() ), contained.value() ) );
1779 }
1780
1781#endif
1782
1783 constexpr explicit operator bool() const noexcept
1784 {
1785 return has_value();
1786 }
1787
1788 constexpr bool has_value() const noexcept
1789 {
1790 return contained.has_value();
1791 }
1792
1793 constexpr value_type const & value() const &
1794 {
1795 return has_value()
1796 ? ( contained.value() )
1797 : ( error_traits<error_type>::rethrow( contained.error() ), contained.value() );
1798 }
1799
1800 value_type & value() &
1801 {
1802 return has_value()
1803 ? ( contained.value() )
1804 : ( error_traits<error_type>::rethrow( contained.error() ), contained.value() );
1805 }
1806
1807#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490
1808
1809 constexpr value_type const && value() const &&
1810 {
1811 return std::move( has_value()
1812 ? ( contained.value() )
1813 : ( error_traits<error_type>::rethrow( contained.error() ), contained.value() ) );
1814 }
1815
1816 nsel_constexpr14 value_type && value() &&
1817 {
1818 return std::move( has_value()
1819 ? ( contained.value() )
1820 : ( error_traits<error_type>::rethrow( contained.error() ), contained.value() ) );
1821 }
1822
1823#endif
1824
1825 constexpr error_type const & error() const &
1826 {
1827 return assert( ! has_value() ), contained.error();
1828 }
1829
1830 error_type & error() &
1831 {
1832 return assert( ! has_value() ), contained.error();
1833 }
1834
1835#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490
1836
1837 constexpr error_type const && error() const &&
1838 {
1839 return std::move( ( assert( ! has_value() ), contained.error() ) );
1840 }
1841
1842 error_type && error() &&
1843 {
1844 return std::move( ( assert( ! has_value() ), contained.error() ) );
1845 }
1846
1847#endif
1848
1849 constexpr unexpected_type get_unexpected() const
1850 {
1851 return make_unexpected( contained.error() );
1852 }
1853
1854 template< typename Ex >
1855 bool has_exception() const
1856 {
1857 using ContainedEx = typename std::remove_reference< decltype( get_unexpected().value() ) >::type;
1858 return ! has_value() && std::is_base_of< Ex, ContainedEx>::value;
1859 }
1860
1861 template< typename U
1863 std::is_copy_constructible< T>::value
1864 && std::is_convertible<U&&, T>::value
1865 )
1866 >
1867 value_type value_or( U && v ) const &
1868 {
1869 return has_value()
1870 ? contained.value()
1871 : static_cast<T>( std::forward<U>( v ) );
1872 }
1873
1874 template< typename U
1876 std::is_move_constructible< T>::value
1877 && std::is_convertible<U&&, T>::value
1878 )
1879 >
1880 value_type value_or( U && v ) &&
1881 {
1882 return has_value()
1883 ? std::move( contained.value() )
1884 : static_cast<T>( std::forward<U>( v ) );
1885 }
1886
1887 // unwrap()
1888
1889// template <class U, class E>
1890// constexpr expected<U,E> expected<expected<U,E>,E>::unwrap() const&;
1891
1892// template <class T, class E>
1893// constexpr expected<T,E> expected<T,E>::unwrap() const&;
1894
1895// template <class U, class E>
1896// expected<U,E> expected<expected<U,E>, E>::unwrap() &&;
1897
1898// template <class T, class E>
1899// template expected<T,E> expected<T,E>::unwrap() &&;
1900
1901 // factories
1902
1903// template< typename Ex, typename F>
1904// expected<T,E> catch_exception(F&& f);
1905
1906// template< typename F>
1907// expected<decltype(func(declval<T>())),E> map(F&& func) ;
1908
1909// template< typename F>
1910// 'see below' bind(F&& func);
1911
1912// template< typename F>
1913// expected<T,E> catch_error(F&& f);
1914
1915// template< typename F>
1916// 'see below' then(F&& func);
1917
1918private:
1919 detail::storage_t
1920 <
1921 T
1922 ,E
1923 , std::is_copy_constructible<T>::value && std::is_copy_constructible<E>::value
1924 , std::is_move_constructible<T>::value && std::is_move_constructible<E>::value
1925 >
1926 contained;
1927};
1928
1930
1931template< typename E >
1932class expected<void, E>
1933{
1934private:
1935 template< typename, typename > friend class expected;
1936
1937public:
1938 using value_type = void;
1939 using error_type = E;
1940 using unexpected_type = nonstd::unexpected_type<E>;
1941
1942 // x.x.4.1 constructors
1943
1944 constexpr expected() noexcept
1945 : contained( true )
1946 {}
1947
1948 nsel_constexpr14 expected( expected const & other ) = default;
1949 nsel_constexpr14 expected( expected && other ) = default;
1950
1951 constexpr explicit expected( nonstd_lite_in_place_t(void) )
1952 : contained( true )
1953 {}
1954
1955 template< typename G = E
1957 !std::is_convertible<G const &, E>::value /*=> explicit */
1958 )
1959 >
1960 nsel_constexpr14 explicit expected( nonstd::unexpected_type<G> const & error )
1961 : contained( false )
1962 {
1963 contained.construct_error( E{ error.value() } );
1964 }
1965
1966 template< typename G = E
1968 std::is_convertible<G const &, E>::value /*=> non-explicit */
1969 )
1970 >
1971 nsel_constexpr14 /*non-explicit*/ expected( nonstd::unexpected_type<G> const & error )
1972 : contained( false )
1973 {
1974 contained.construct_error( error.value() );
1975 }
1976
1977 template< typename G = E
1979 !std::is_convertible<G&&, E>::value /*=> explicit */
1980 )
1981 >
1982 nsel_constexpr14 explicit expected( nonstd::unexpected_type<G> && error )
1983 : contained( false )
1984 {
1985 contained.construct_error( E{ std::move( error.value() ) } );
1986 }
1987
1988 template< typename G = E
1990 std::is_convertible<G&&, E>::value /*=> non-explicit */
1991 )
1992 >
1993 nsel_constexpr14 /*non-explicit*/ expected( nonstd::unexpected_type<G> && error )
1994 : contained( false )
1995 {
1996 contained.construct_error( std::move( error.value() ) );
1997 }
1998
1999 template< typename... Args
2001 std::is_constructible<E, Args&&...>::value
2002 )
2003 >
2004 nsel_constexpr14 explicit expected( unexpect_t, Args&&... args )
2005 : contained( false )
2006 {
2007 contained.emplace_error( std::forward<Args>( args )... );
2008 }
2009
2010 template< typename U, typename... Args
2012 std::is_constructible<E, std::initializer_list<U>, Args&&...>::value
2013 )
2014 >
2015 nsel_constexpr14 explicit expected( unexpect_t, std::initializer_list<U> il, Args&&... args )
2016 : contained( false )
2017 {
2018 contained.emplace_error( il, std::forward<Args>( args )... );
2019 }
2020
2021 // destructor
2022
2023 ~expected()
2024 {
2025 if ( ! has_value() )
2026 {
2027 contained.destruct_error();
2028 }
2029 }
2030
2031 // x.x.4.3 assignment
2032
2033 expected & operator=( expected const & other )
2034 {
2035 expected( other ).swap( *this );
2036 return *this;
2037 }
2038
2039 expected & operator=( expected && other ) noexcept
2040 (
2041 std::is_nothrow_move_assignable<E>::value &&
2042 std::is_nothrow_move_constructible<E>::value )
2043 {
2044 expected( std::move( other ) ).swap( *this );
2045 return *this;
2046 }
2047
2048 void emplace()
2049 {
2050 expected().swap( *this );
2051 }
2052
2053 // x.x.4.4 swap
2054
2055 template< typename G = E >
2056 nsel_REQUIRES_R( void,
2057 std17::is_swappable<G>::value
2058 && std::is_move_constructible<G>::value
2059 )
2060 swap( expected & other ) noexcept
2061 (
2062 std::is_nothrow_move_constructible<E>::value && std17::is_nothrow_swappable<E&>::value
2063 )
2064 {
2065 using std::swap;
2066
2067 if ( ! bool(*this) && ! bool(other) ) { swap( contained.error(), other.contained.error() ); }
2068 else if ( bool(*this) && ! bool(other) ) { contained.construct_error( std::move( other.error() ) );
2069 bool has_value = contained.has_value();
2070 bool other_has_value = other.has_value();
2071 other.contained.set_has_value(has_value);
2072 contained.set_has_value(other_has_value);
2073 }
2074 else if ( ! bool(*this) && bool(other) ) { other.swap( *this ); }
2075 }
2076
2077 // x.x.4.5 observers
2078
2079 constexpr explicit operator bool() const noexcept
2080 {
2081 return has_value();
2082 }
2083
2084 constexpr bool has_value() const noexcept
2085 {
2086 return contained.has_value();
2087 }
2088
2089 void value() const
2090 {
2091 if ( ! has_value() )
2092 {
2093 error_traits<error_type>::rethrow( contained.error() );
2094 }
2095 }
2096
2097 constexpr error_type const & error() const &
2098 {
2099 return assert( ! has_value() ), contained.error();
2100 }
2101
2102 error_type & error() &
2103 {
2104 return assert( ! has_value() ), contained.error();
2105 }
2106
2107#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490
2108
2109 constexpr error_type const && error() const &&
2110 {
2111 return std::move( ( assert( ! has_value() ), contained.error() ) );
2112 }
2113
2114 error_type && error() &&
2115 {
2116 return std::move( ( assert( ! has_value() ), contained.error() ) );
2117 }
2118
2119#endif
2120
2121 constexpr unexpected_type get_unexpected() const
2122 {
2123 return make_unexpected( contained.error() );
2124 }
2125
2126 template< typename Ex >
2127 bool has_exception() const
2128 {
2129 using ContainedEx = typename std::remove_reference< decltype( get_unexpected().value() ) >::type;
2130 return ! has_value() && std::is_base_of< Ex, ContainedEx>::value;
2131 }
2132
2133// template constexpr 'see below' unwrap() const&;
2134//
2135// template 'see below' unwrap() &&;
2136
2137 // factories
2138
2139// template< typename Ex, typename F>
2140// expected<void,E> catch_exception(F&& f);
2141//
2142// template< typename F>
2143// expected<decltype(func()), E> map(F&& func) ;
2144//
2145// template< typename F>
2146// 'see below' bind(F&& func) ;
2147//
2148// template< typename F>
2149// expected<void,E> catch_error(F&& f);
2150//
2151// template< typename F>
2152// 'see below' then(F&& func);
2153
2154private:
2155 detail::storage_t
2156 <
2157 void
2158 , E
2159 , std::is_copy_constructible<E>::value
2160 , std::is_move_constructible<E>::value
2161 >
2162 contained;
2163};
2164
2165// x.x.4.6 expected<>: comparison operators
2166
2167template< typename T1, typename E1, typename T2, typename E2 >
2168constexpr bool operator==( expected<T1,E1> const & x, expected<T2,E2> const & y )
2169{
2170 return bool(x) != bool(y) ? false : bool(x) == false ? x.error() == y.error() : *x == *y;
2171}
2172
2173template< typename T1, typename E1, typename T2, typename E2 >
2174constexpr bool operator!=( expected<T1,E1> const & x, expected<T2,E2> const & y )
2175{
2176 return !(x == y);
2177}
2178
2179template< typename E1, typename E2 >
2180constexpr bool operator==( expected<void,E1> const & x, expected<void,E1> const & y )
2181{
2182 return bool(x) != bool(y) ? false : bool(x) == false ? x.error() == y.error() : true;
2183}
2184
2185#if nsel_P0323R <= 2
2186
2187template< typename T, typename E >
2188constexpr bool operator<( expected<T,E> const & x, expected<T,E> const & y )
2189{
2190 return (!y) ? false : (!x) ? true : *x < *y;
2191}
2192
2193template< typename T, typename E >
2194constexpr bool operator>( expected<T,E> const & x, expected<T,E> const & y )
2195{
2196 return (y < x);
2197}
2198
2199template< typename T, typename E >
2200constexpr bool operator<=( expected<T,E> const & x, expected<T,E> const & y )
2201{
2202 return !(y < x);
2203}
2204
2205template< typename T, typename E >
2206constexpr bool operator>=( expected<T,E> const & x, expected<T,E> const & y )
2207{
2208 return !(x < y);
2209}
2210
2211#endif
2212
2213// x.x.4.7 expected: comparison with T
2214
2215template< typename T1, typename E1, typename T2 >
2216constexpr bool operator==( expected<T1,E1> const & x, T2 const & v )
2217{
2218 return bool(x) ? *x == v : false;
2219}
2220
2221template< typename T1, typename E1, typename T2 >
2222constexpr bool operator==(T2 const & v, expected<T1,E1> const & x )
2223{
2224 return bool(x) ? v == *x : false;
2225}
2226
2227template< typename T1, typename E1, typename T2 >
2228constexpr bool operator!=( expected<T1,E1> const & x, T2 const & v )
2229{
2230 return bool(x) ? *x != v : true;
2231}
2232
2233template< typename T1, typename E1, typename T2 >
2234constexpr bool operator!=( T2 const & v, expected<T1,E1> const & x )
2235{
2236 return bool(x) ? v != *x : true;
2237}
2238
2239#if nsel_P0323R <= 2
2240
2241template< typename T, typename E >
2242constexpr bool operator<( expected<T,E> const & x, T const & v )
2243{
2244 return bool(x) ? *x < v : true;
2245}
2246
2247template< typename T, typename E >
2248constexpr bool operator<( T const & v, expected<T,E> const & x )
2249{
2250 return bool(x) ? v < *x : false;
2251}
2252
2253template< typename T, typename E >
2254constexpr bool operator>( T const & v, expected<T,E> const & x )
2255{
2256 return bool(x) ? *x < v : false;
2257}
2258
2259template< typename T, typename E >
2260constexpr bool operator>( expected<T,E> const & x, T const & v )
2261{
2262 return bool(x) ? v < *x : false;
2263}
2264
2265template< typename T, typename E >
2266constexpr bool operator<=( T const & v, expected<T,E> const & x )
2267{
2268 return bool(x) ? ! ( *x < v ) : false;
2269}
2270
2271template< typename T, typename E >
2272constexpr bool operator<=( expected<T,E> const & x, T const & v )
2273{
2274 return bool(x) ? ! ( v < *x ) : true;
2275}
2276
2277template< typename T, typename E >
2278constexpr bool operator>=( expected<T,E> const & x, T const & v )
2279{
2280 return bool(x) ? ! ( *x < v ) : false;
2281}
2282
2283template< typename T, typename E >
2284constexpr bool operator>=( T const & v, expected<T,E> const & x )
2285{
2286 return bool(x) ? ! ( v < *x ) : true;
2287}
2288
2289#endif // nsel_P0323R
2290
2291// x.x.4.8 expected: comparison with unexpected_type
2292
2293template< typename T1, typename E1 , typename E2 >
2294constexpr bool operator==( expected<T1,E1> const & x, unexpected_type<E2> const & u )
2295{
2296 return (!x) ? x.get_unexpected() == u : false;
2297}
2298
2299template< typename T1, typename E1 , typename E2 >
2300constexpr bool operator==( unexpected_type<E2> const & u, expected<T1,E1> const & x )
2301{
2302 return ( x == u );
2303}
2304
2305template< typename T1, typename E1 , typename E2 >
2306constexpr bool operator!=( expected<T1,E1> const & x, unexpected_type<E2> const & u )
2307{
2308 return ! ( x == u );
2309}
2310
2311template< typename T1, typename E1 , typename E2 >
2312constexpr bool operator!=( unexpected_type<E2> const & u, expected<T1,E1> const & x )
2313{
2314 return ! ( x == u );
2315}
2316
2317#if nsel_P0323R <= 2
2318
2319template< typename T, typename E >
2320constexpr bool operator<( expected<T,E> const & x, unexpected_type<E> const & u )
2321{
2322 return (!x) ? ( x.get_unexpected() < u ) : false;
2323}
2324
2325template< typename T, typename E >
2326constexpr bool operator<( unexpected_type<E> const & u, expected<T,E> const & x )
2327{
2328 return (!x) ? ( u < x.get_unexpected() ) : true ;
2329}
2330
2331template< typename T, typename E >
2332constexpr bool operator>( expected<T,E> const & x, unexpected_type<E> const & u )
2333{
2334 return ( u < x );
2335}
2336
2337template< typename T, typename E >
2338constexpr bool operator>( unexpected_type<E> const & u, expected<T,E> const & x )
2339{
2340 return ( x < u );
2341}
2342
2343template< typename T, typename E >
2344constexpr bool operator<=( expected<T,E> const & x, unexpected_type<E> const & u )
2345{
2346 return ! ( u < x );
2347}
2348
2349template< typename T, typename E >
2350constexpr bool operator<=( unexpected_type<E> const & u, expected<T,E> const & x)
2351{
2352 return ! ( x < u );
2353}
2354
2355template< typename T, typename E >
2356constexpr bool operator>=( expected<T,E> const & x, unexpected_type<E> const & u )
2357{
2358 return ! ( u > x );
2359}
2360
2361template< typename T, typename E >
2362constexpr bool operator>=( unexpected_type<E> const & u, expected<T,E> const & x )
2363{
2364 return ! ( x > u );
2365}
2366
2367#endif // nsel_P0323R
2368
2370
2371template< typename T, typename E
2373 ( std::is_void<T>::value || std::is_move_constructible<T>::value )
2374 && std::is_move_constructible<E>::value
2375 && std17::is_swappable<T>::value
2376 && std17::is_swappable<E>::value )
2377>
2378void swap( expected<T,E> & x, expected<T,E> & y ) noexcept ( noexcept ( x.swap(y) ) )
2379{
2380 x.swap( y );
2381}
2382
2383#if nsel_P0323R <= 3
2384
2385template< typename T >
2386constexpr auto make_expected( T && v ) -> expected< typename std::decay<T>::type >
2387{
2388 return expected< typename std::decay<T>::type >( std::forward<T>( v ) );
2389}
2390
2391// expected<void> specialization:
2392
2393auto inline make_expected() -> expected<void>
2394{
2395 return expected<void>( in_place );
2396}
2397
2398template< typename T >
2399constexpr auto make_expected_from_current_exception() -> expected<T>
2400{
2401 return expected<T>( make_unexpected_from_current_exception() );
2402}
2403
2404template< typename T >
2405auto make_expected_from_exception( std::exception_ptr v ) -> expected<T>
2406{
2407 return expected<T>( unexpected_type<std::exception_ptr>( std::forward<std::exception_ptr>( v ) ) );
2408}
2409
2410template< typename T, typename E >
2411constexpr auto make_expected_from_error( E e ) -> expected<T, typename std::decay<E>::type>
2412{
2413 return expected<T, typename std::decay<E>::type>( make_unexpected( e ) );
2414}
2415
2416template< typename F
2417 nsel_REQUIRES_T( ! std::is_same<typename std::result_of<F()>::type, void>::value )
2418>
2419/*nsel_constexpr14*/
2420auto make_expected_from_call( F f ) -> expected< typename std::result_of<F()>::type >
2421{
2422 try
2423 {
2424 return make_expected( f() );
2425 }
2426 catch (...)
2427 {
2428 return make_unexpected_from_current_exception();
2429 }
2430}
2431
2432template< typename F
2433 nsel_REQUIRES_T( std::is_same<typename std::result_of<F()>::type, void>::value )
2434>
2435/*nsel_constexpr14*/
2436auto make_expected_from_call( F f ) -> expected<void>
2437{
2438 try
2439 {
2440 f();
2441 return make_expected();
2442 }
2443 catch (...)
2444 {
2445 return make_unexpected_from_current_exception();
2446 }
2447}
2448
2449#endif // nsel_P0323R
2450
2451} // namespace expected_lite
2452
2453using namespace expected_lite;
2454
2455// using expected_lite::expected;
2456// using ...
2457
2458} // namespace nonstd
2459
2460namespace std {
2461
2462// expected: hash support
2463
2464template< typename T, typename E >
2465struct hash< nonstd::expected<T,E> >
2466{
2467 using result_type = std::size_t;
2468 using argument_type = nonstd::expected<T,E>;
2469
2470 constexpr result_type operator()(argument_type const & arg) const
2471 {
2472 return arg ? std::hash<T>{}(*arg) : result_type{};
2473 }
2474};
2475
2476// TBD - ?? remove? see spec.
2477template< typename T, typename E >
2478struct hash< nonstd::expected<T&,E> >
2479{
2480 using result_type = std::size_t;
2481 using argument_type = nonstd::expected<T&,E>;
2482
2483 constexpr result_type operator()(argument_type const & arg) const
2484 {
2485 return arg ? std::hash<T>{}(*arg) : result_type{};
2486 }
2487};
2488
2489// TBD - implement
2490// bool(e), hash<expected<void,E>>()(e) shall evaluate to the hashing true;
2491// otherwise it evaluates to an unspecified value if E is exception_ptr or
2492// a combination of hashing false and hash<E>()(e.error()).
2493
2494template< typename E >
2495struct hash< nonstd::expected<void,E> >
2496{
2497};
2498
2499} // namespace std
2500
2501namespace nonstd {
2502
2503// void unexpected() is deprecated && removed in C++17
2504
2505#if nsel_CPP17_OR_GREATER || nsel_COMPILER_MSVC_VERSION > 141
2506template< typename E >
2507using unexpected = unexpected_type<E>;
2508#endif
2509
2510} // namespace nonstd
2511
2512#undef nsel_REQUIRES
2513#undef nsel_REQUIRES_0
2514#undef nsel_REQUIRES_T
2515
2517
2518#endif // nsel_USES_STD_EXPECTED
2519
2520#endif // NONSTD_EXPECTED_LITE_HPP
in_place_t in_place_type(detail::in_place_type_tag< T >=detail::in_place_type_tag< T >())
Definition: expected.hpp:182
in_place_t in_place_index(detail::in_place_index_tag< K >=detail::in_place_index_tag< K >())
Definition: expected.hpp:188
in_place_t in_place(detail::in_place_type_tag< T >=detail::in_place_type_tag< T >())
Definition: expected.hpp:170
STL namespace.
nonstd::expected< T, E > argument_type
Definition: expected.hpp:2468
constexpr result_type operator()(argument_type const &arg) const
Definition: expected.hpp:2470
nonstd::expected< T &, E > argument_type
Definition: expected.hpp:2481
constexpr result_type operator()(argument_type const &arg) const
Definition: expected.hpp:2483
#define nsel_inline17
Definition: expected.hpp:263
#define nsel_REQUIRES_T(...)
Definition: expected.hpp:310
#define nsel_RESTORE_WARNINGS()
Definition: expected.hpp:351
#define nonstd_lite_in_place( T)
Definition: expected.hpp:199
#define nsel_REQUIRES_0(...)
Definition: expected.hpp:307
#define nsel_constexpr14
Definition: expected.hpp:257
#define nonstd_lite_in_place_t( T)
Definition: expected.hpp:195
#define nsel_REQUIRES_R(R,...)
Definition: expected.hpp:313
#define nsel_DISABLE_MSVC_WARNINGS(codes)
Definition: expected.hpp:341