2 // Copyright (c) 2014-2018 Martin Moene
4 // https://github.com/martinmoene/optional-lite
6 // Distributed under the Boost Software License, Version 1.0.
7 // (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
11 #ifndef NONSTD_OPTIONAL_LITE_HPP
12 #define NONSTD_OPTIONAL_LITE_HPP
14 #define optional_lite_MAJOR 3
15 #define optional_lite_MINOR 2
16 #define optional_lite_PATCH 0
18 #define optional_lite_VERSION optional_STRINGIFY(optional_lite_MAJOR) "." optional_STRINGIFY(optional_lite_MINOR) "." optional_STRINGIFY(optional_lite_PATCH)
20 #define optional_STRINGIFY( x ) optional_STRINGIFY_( x )
21 #define optional_STRINGIFY_( x ) #x
23 // optional-lite configuration:
25 #define optional_OPTIONAL_DEFAULT 0
26 #define optional_OPTIONAL_NONSTD 1
27 #define optional_OPTIONAL_STD 2
29 #if !defined( optional_CONFIG_SELECT_OPTIONAL )
30 # define optional_CONFIG_SELECT_OPTIONAL ( optional_HAVE_STD_OPTIONAL ? optional_OPTIONAL_STD : optional_OPTIONAL_NONSTD )
33 // Control presence of exception handling (try and auto discover):
35 #ifndef optional_CONFIG_NO_EXCEPTIONS
36 # if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)
37 # define optional_CONFIG_NO_EXCEPTIONS 0
39 # define optional_CONFIG_NO_EXCEPTIONS 1
43 // C++ language version detection (C++20 is speculative):
44 // Note: VC14.0/1900 (VS2015) lacks too much from C++14.
46 #ifndef optional_CPLUSPLUS
47 # if defined(_MSVC_LANG ) && !defined(__clang__)
48 # define optional_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG )
50 # define optional_CPLUSPLUS __cplusplus
54 #define optional_CPP98_OR_GREATER ( optional_CPLUSPLUS >= 199711L )
55 #define optional_CPP11_OR_GREATER ( optional_CPLUSPLUS >= 201103L )
56 #define optional_CPP11_OR_GREATER_ ( optional_CPLUSPLUS >= 201103L )
57 #define optional_CPP14_OR_GREATER ( optional_CPLUSPLUS >= 201402L )
58 #define optional_CPP17_OR_GREATER ( optional_CPLUSPLUS >= 201703L )
59 #define optional_CPP20_OR_GREATER ( optional_CPLUSPLUS >= 202000L )
61 // C++ language version (represent 98 as 3):
63 #define optional_CPLUSPLUS_V ( optional_CPLUSPLUS / 100 - (optional_CPLUSPLUS > 200000 ? 2000 : 1994) )
65 // Use C++17 std::optional if available and requested:
67 #if optional_CPP17_OR_GREATER && defined(__has_include )
68 # if __has_include( <optional> )
69 # define optional_HAVE_STD_OPTIONAL 1
71 # define optional_HAVE_STD_OPTIONAL 0
74 # define optional_HAVE_STD_OPTIONAL 0
77 #define optional_USES_STD_OPTIONAL ( (optional_CONFIG_SELECT_OPTIONAL == optional_OPTIONAL_STD) || ((optional_CONFIG_SELECT_OPTIONAL == optional_OPTIONAL_DEFAULT) && optional_HAVE_STD_OPTIONAL) )
80 // in_place: code duplicated in any-lite, expected-lite, optional-lite, value-ptr-lite, variant-lite:
83 #ifndef nonstd_lite_HAVE_IN_PLACE_TYPES
84 #define nonstd_lite_HAVE_IN_PLACE_TYPES 1
86 // C++17 std::in_place in <utility>:
88 #if optional_CPP17_OR_GREATER
95 using std::in_place_type;
96 using std::in_place_index;
97 using std::in_place_t;
98 using std::in_place_type_t;
99 using std::in_place_index_t;
101 #define nonstd_lite_in_place_t( T) std::in_place_t
102 #define nonstd_lite_in_place_type_t( T) std::in_place_type_t<T>
103 #define nonstd_lite_in_place_index_t(K) std::in_place_index_t<K>
105 #define nonstd_lite_in_place( T) std::in_place_t{}
106 #define nonstd_lite_in_place_type( T) std::in_place_type_t<T>{}
107 #define nonstd_lite_in_place_index(K) std::in_place_index_t<K>{}
109 } // namespace nonstd
111 #else // optional_CPP17_OR_GREATER
119 struct in_place_type_tag {};
121 template< std::size_t K >
122 struct in_place_index_tag {};
124 } // namespace detail
126 struct in_place_t {};
129 inline in_place_t in_place( detail::in_place_type_tag<T> /*unused*/ = detail::in_place_type_tag<T>() )
134 template< std::size_t K >
135 inline in_place_t in_place( detail::in_place_index_tag<K> /*unused*/ = detail::in_place_index_tag<K>() )
141 inline in_place_t in_place_type( detail::in_place_type_tag<T> /*unused*/ = detail::in_place_type_tag<T>() )
146 template< std::size_t K >
147 inline in_place_t in_place_index( detail::in_place_index_tag<K> /*unused*/ = detail::in_place_index_tag<K>() )
152 // mimic templated typedef:
154 #define nonstd_lite_in_place_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag<T> )
155 #define nonstd_lite_in_place_type_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag<T> )
156 #define nonstd_lite_in_place_index_t(K) nonstd::in_place_t(&)( nonstd::detail::in_place_index_tag<K> )
158 #define nonstd_lite_in_place( T) nonstd::in_place_type<T>
159 #define nonstd_lite_in_place_type( T) nonstd::in_place_type<T>
160 #define nonstd_lite_in_place_index(K) nonstd::in_place_index<K>
162 } // namespace nonstd
164 #endif // optional_CPP17_OR_GREATER
165 #endif // nonstd_lite_HAVE_IN_PLACE_TYPES
168 // Using std::optional:
171 #if optional_USES_STD_OPTIONAL
178 using std::bad_optional_access;
182 using std::nullopt_t;
184 using std::operator==;
185 using std::operator!=;
186 using std::operator<;
187 using std::operator<=;
188 using std::operator>;
189 using std::operator>=;
190 using std::make_optional;
194 #else // optional_USES_STD_OPTIONAL
199 // optional-lite alignment configuration:
201 #ifndef optional_CONFIG_MAX_ALIGN_HACK
202 # define optional_CONFIG_MAX_ALIGN_HACK 0
205 #ifndef optional_CONFIG_ALIGN_AS
206 // no default, used in #if defined()
209 #ifndef optional_CONFIG_ALIGN_AS_FALLBACK
210 # define optional_CONFIG_ALIGN_AS_FALLBACK double
213 // Compiler warning suppression:
215 #if defined(__clang__)
216 # pragma clang diagnostic push
217 # pragma clang diagnostic ignored "-Wundef"
218 #elif defined(__GNUC__)
219 # pragma GCC diagnostic push
220 # pragma GCC diagnostic ignored "-Wundef"
221 #elif defined(_MSC_VER )
222 # pragma warning( push )
225 // half-open range [lo..hi):
226 #define optional_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) )
228 // Compiler versions:
230 // MSVC++ 6.0 _MSC_VER == 1200 (Visual Studio 6.0)
231 // MSVC++ 7.0 _MSC_VER == 1300 (Visual Studio .NET 2002)
232 // MSVC++ 7.1 _MSC_VER == 1310 (Visual Studio .NET 2003)
233 // MSVC++ 8.0 _MSC_VER == 1400 (Visual Studio 2005)
234 // MSVC++ 9.0 _MSC_VER == 1500 (Visual Studio 2008)
235 // MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010)
236 // MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012)
237 // MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013)
238 // MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015)
239 // MSVC++ 14.1 _MSC_VER >= 1910 (Visual Studio 2017)
241 #if defined(_MSC_VER ) && !defined(__clang__)
242 # define optional_COMPILER_MSVC_VER (_MSC_VER )
243 # define optional_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900 ) ) )
245 # define optional_COMPILER_MSVC_VER 0
246 # define optional_COMPILER_MSVC_VERSION 0
249 #define optional_COMPILER_VERSION( major, minor, patch ) ( 10 * (10 * (major) + (minor) ) + (patch) )
251 #if defined(__GNUC__) && !defined(__clang__)
252 # define optional_COMPILER_GNUC_VERSION optional_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
254 # define optional_COMPILER_GNUC_VERSION 0
257 #if defined(__clang__)
258 # define optional_COMPILER_CLANG_VERSION optional_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__)
260 # define optional_COMPILER_CLANG_VERSION 0
263 #if optional_BETWEEN(optional_COMPILER_MSVC_VERSION, 70, 140 )
264 # pragma warning( disable: 4345 ) // initialization behavior changed
267 #if optional_BETWEEN(optional_COMPILER_MSVC_VERSION, 70, 150 )
268 # pragma warning( disable: 4814 ) // in C++14 'constexpr' will not imply 'const'
271 // Presence of language and library features:
273 #define optional_HAVE(FEATURE) ( optional_HAVE_##FEATURE )
276 # define optional_HAS_CPP0X _HAS_CPP0X
278 # define optional_HAS_CPP0X 0
281 // Unless defined otherwise below, consider VC14 as C++11 for optional-lite:
283 #if optional_COMPILER_MSVC_VER >= 1900
284 # undef optional_CPP11_OR_GREATER
285 # define optional_CPP11_OR_GREATER 1
288 #define optional_CPP11_90 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1500)
289 #define optional_CPP11_100 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1600)
290 #define optional_CPP11_110 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1700)
291 #define optional_CPP11_120 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1800)
292 #define optional_CPP11_140 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1900)
293 #define optional_CPP11_141 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1910)
295 #define optional_CPP14_000 (optional_CPP14_OR_GREATER)
296 #define optional_CPP17_000 (optional_CPP17_OR_GREATER)
298 // Presence of C++11 language features:
300 #define optional_HAVE_CONSTEXPR_11 optional_CPP11_140
301 #define optional_HAVE_IS_DEFAULT optional_CPP11_140
302 #define optional_HAVE_NOEXCEPT optional_CPP11_140
303 #define optional_HAVE_NULLPTR optional_CPP11_100
304 #define optional_HAVE_REF_QUALIFIER optional_CPP11_140
306 // Presence of C++14 language features:
308 #define optional_HAVE_CONSTEXPR_14 optional_CPP14_000
310 // Presence of C++17 language features:
312 #define optional_HAVE_NODISCARD optional_CPP17_000
314 // Presence of C++ library features:
316 #define optional_HAVE_CONDITIONAL optional_CPP11_120
317 #define optional_HAVE_REMOVE_CV optional_CPP11_120
318 #define optional_HAVE_TYPE_TRAITS optional_CPP11_90
320 #define optional_HAVE_TR1_TYPE_TRAITS (!! optional_COMPILER_GNUC_VERSION )
321 #define optional_HAVE_TR1_ADD_POINTER (!! optional_COMPILER_GNUC_VERSION )
323 // C++ feature usage:
325 #if optional_HAVE( CONSTEXPR_11 )
326 # define optional_constexpr constexpr
328 # define optional_constexpr /*constexpr*/
331 #if optional_HAVE( IS_DEFAULT )
332 # define optional_is_default = default;
334 # define optional_is_default {}
337 #if optional_HAVE( CONSTEXPR_14 )
338 # define optional_constexpr14 constexpr
340 # define optional_constexpr14 /*constexpr*/
343 #if optional_HAVE( NODISCARD )
344 # define optional_nodiscard [[nodiscard]]
346 # define optional_nodiscard /*[[nodiscard]]*/
349 #if optional_HAVE( NOEXCEPT )
350 # define optional_noexcept noexcept
352 # define optional_noexcept /*noexcept*/
355 #if optional_HAVE( NULLPTR )
356 # define optional_nullptr nullptr
358 # define optional_nullptr NULL
361 #if optional_HAVE( REF_QUALIFIER )
362 // NOLINTNEXTLINE( bugprone-macro-parentheses )
363 # define optional_ref_qual &
364 # define optional_refref_qual &&
366 # define optional_ref_qual /*&*/
367 # define optional_refref_qual /*&&*/
370 // additional includes:
372 #if optional_CONFIG_NO_EXCEPTIONS
373 // already included: <cassert>
375 # include <stdexcept>
378 #if optional_CPP11_OR_GREATER
379 # include <functional>
382 #if optional_HAVE( INITIALIZER_LIST )
383 # include <initializer_list>
386 #if optional_HAVE( TYPE_TRAITS )
387 # include <type_traits>
388 #elif optional_HAVE( TR1_TYPE_TRAITS )
389 # include <tr1/type_traits>
394 #if optional_CPP11_OR_GREATER
396 #define optional_REQUIRES_0(...) \
397 template< bool B = (__VA_ARGS__), typename std::enable_if<B, int>::type = 0 >
399 #define optional_REQUIRES_T(...) \
400 , typename = typename std::enable_if< (__VA_ARGS__), nonstd::optional_lite::detail::enabler >::type
402 #define optional_REQUIRES_R(R, ...) \
403 typename std::enable_if< (__VA_ARGS__), R>::type
405 #define optional_REQUIRES_A(...) \
406 , typename std::enable_if< (__VA_ARGS__), void*>::type = nullptr
414 namespace nonstd { namespace optional_lite {
418 #if optional_CPP11_OR_GREATER
421 template< typename T > T & move( T & t ) { return t; }
424 #if optional_HAVE( CONDITIONAL )
425 using std::conditional;
427 template< bool B, typename T, typename F > struct conditional { typedef T type; };
428 template< typename T, typename F > struct conditional<false, T, F> { typedef F type; };
429 #endif // optional_HAVE_CONDITIONAL
433 #if optional_CPP11_OR_GREATER
435 /// type traits C++17:
439 #if optional_CPP17_OR_GREATER
441 using std::is_swappable;
442 using std::is_nothrow_swappable;
444 #elif optional_CPP11_OR_GREATER
452 template< typename T, typename = decltype( swap( std::declval<T&>(), std::declval<T&>() ) ) >
453 static std::true_type test( int /*unused*/ );
456 static std::false_type test(...);
459 struct is_nothrow_swappable
461 // wrap noexcept(expr) in separate function as work-around for VC140 (VS2015):
463 template< typename T >
464 static constexpr bool satisfies()
466 return noexcept( swap( std::declval<T&>(), std::declval<T&>() ) );
469 template< typename T >
470 static auto test( int /*unused*/ ) -> std::integral_constant<bool, satisfies<T>()>{}
473 static auto test(...) -> std::false_type;
476 } // namespace detail
478 // is [nothow] swappable:
480 template< typename T >
481 struct is_swappable : decltype( detail::is_swappable::test<T>(0) ){};
483 template< typename T >
484 struct is_nothrow_swappable : decltype( detail::is_nothrow_swappable::test<T>(0) ){};
486 #endif // optional_CPP17_OR_GREATER
490 /// type traits C++20:
494 template< typename T >
497 typedef typename std::remove_cv< typename std::remove_reference<T>::type >::type type;
502 #endif // optional_CPP11_OR_GREATER
506 template< typename T >
511 // for optional_REQUIRES_T
513 #if optional_CPP11_OR_GREATER
514 enum class enabler{};
521 template< typename Head, typename Tail >
528 #if optional_CONFIG_MAX_ALIGN_HACK
530 // Max align, use most restricted type for alignment:
532 #define optional_UNIQUE( name ) optional_UNIQUE2( name, __LINE__ )
533 #define optional_UNIQUE2( name, line ) optional_UNIQUE3( name, line )
534 #define optional_UNIQUE3( name, line ) name ## line
536 #define optional_ALIGN_TYPE( type ) \
537 type optional_UNIQUE( _t ); struct_t< type > optional_UNIQUE( _st )
539 template< typename T >
540 struct struct_t { T _; };
544 optional_ALIGN_TYPE( char );
545 optional_ALIGN_TYPE( short int );
546 optional_ALIGN_TYPE( int );
547 optional_ALIGN_TYPE( long int );
548 optional_ALIGN_TYPE( float );
549 optional_ALIGN_TYPE( double );
550 optional_ALIGN_TYPE( long double );
551 optional_ALIGN_TYPE( char * );
552 optional_ALIGN_TYPE( short int * );
553 optional_ALIGN_TYPE( int * );
554 optional_ALIGN_TYPE( long int * );
555 optional_ALIGN_TYPE( float * );
556 optional_ALIGN_TYPE( double * );
557 optional_ALIGN_TYPE( long double * );
558 optional_ALIGN_TYPE( void * );
560 #ifdef HAVE_LONG_LONG
561 optional_ALIGN_TYPE( long long );
566 Unknown ( * optional_UNIQUE(_) )( Unknown );
567 Unknown * Unknown::* optional_UNIQUE(_);
568 Unknown ( Unknown::* optional_UNIQUE(_) )( Unknown );
570 struct_t< Unknown ( * )( Unknown) > optional_UNIQUE(_);
571 struct_t< Unknown * Unknown::* > optional_UNIQUE(_);
572 struct_t< Unknown ( Unknown::* )(Unknown) > optional_UNIQUE(_);
575 #undef optional_UNIQUE
576 #undef optional_UNIQUE2
577 #undef optional_UNIQUE3
579 #undef optional_ALIGN_TYPE
581 #elif defined( optional_CONFIG_ALIGN_AS ) // optional_CONFIG_MAX_ALIGN_HACK
583 // Use user-specified type for alignment:
585 #define optional_ALIGN_AS( unused ) \
586 optional_CONFIG_ALIGN_AS
588 #else // optional_CONFIG_MAX_ALIGN_HACK
590 // Determine POD type to use for alignment:
592 #define optional_ALIGN_AS( to_align ) \
593 typename type_of_size< alignment_types, alignment_of< to_align >::value >::type
595 template< typename T >
598 template< typename T >
599 struct alignment_of_hack
606 template< size_t A, size_t S >
607 struct alignment_logic
609 enum { value = A < S ? A : S };
612 template< typename T >
615 enum { value = alignment_logic<
616 sizeof( alignment_of_hack<T> ) - sizeof(T), sizeof(T) >::value };
619 template< typename List, size_t N >
622 typedef typename std11::conditional<
623 N == sizeof( typename List::head ),
625 typename type_of_size<typename List::tail, N >::type >::type type;
629 struct type_of_size< nulltype, N >
631 typedef optional_CONFIG_ALIGN_AS_FALLBACK type;
634 template< typename T>
635 struct struct_t { T _; };
637 #define optional_ALIGN_TYPE( type ) \
638 typelist< type , typelist< struct_t< type >
643 optional_ALIGN_TYPE( char ),
644 optional_ALIGN_TYPE( short ),
645 optional_ALIGN_TYPE( int ),
646 optional_ALIGN_TYPE( long ),
647 optional_ALIGN_TYPE( float ),
648 optional_ALIGN_TYPE( double ),
649 optional_ALIGN_TYPE( long double ),
651 optional_ALIGN_TYPE( char *),
652 optional_ALIGN_TYPE( short * ),
653 optional_ALIGN_TYPE( int * ),
654 optional_ALIGN_TYPE( long * ),
655 optional_ALIGN_TYPE( float * ),
656 optional_ALIGN_TYPE( double * ),
657 optional_ALIGN_TYPE( long double * ),
659 optional_ALIGN_TYPE( Unknown ( * )( Unknown ) ),
660 optional_ALIGN_TYPE( Unknown * Unknown::* ),
661 optional_ALIGN_TYPE( Unknown ( Unknown::* )( Unknown ) ),
664 > > > > > > > > > > > > > >
665 > > > > > > > > > > > > > >
669 #undef optional_ALIGN_TYPE
671 #endif // optional_CONFIG_MAX_ALIGN_HACK
673 /// C++03 constructed union to hold value.
675 template< typename T >
679 // template< typename > friend class optional;
681 typedef T value_type;
683 storage_t() optional_is_default
685 explicit storage_t( value_type const & v )
687 construct_value( v );
690 void construct_value( value_type const & v )
692 ::new( value_ptr() ) value_type( v );
695 #if optional_CPP11_OR_GREATER
697 explicit storage_t( value_type && v )
699 construct_value( std::move( v ) );
702 void construct_value( value_type && v )
704 ::new( value_ptr() ) value_type( std::move( v ) );
707 template< class... Args >
708 void emplace( Args&&... args )
710 ::new( value_ptr() ) value_type( std::forward<Args>(args)... );
713 template< class U, class... Args >
714 void emplace( std::initializer_list<U> il, Args&&... args )
716 ::new( value_ptr() ) value_type( il, std::forward<Args>(args)... );
721 void destruct_value()
726 optional_nodiscard value_type const * value_ptr() const
728 return as<value_type>();
731 value_type * value_ptr()
733 return as<value_type>();
736 optional_nodiscard value_type const & value() const optional_ref_qual
738 return * value_ptr();
741 value_type & value() optional_ref_qual
743 return * value_ptr();
746 #if optional_CPP11_OR_GREATER
748 optional_nodiscard value_type const && value() const optional_refref_qual
750 return std::move( value() );
753 value_type && value() optional_refref_qual
755 return std::move( value() );
760 #if optional_CPP11_OR_GREATER
762 using aligned_storage_t = typename std::aligned_storage< sizeof(value_type), alignof(value_type) >::type;
763 aligned_storage_t data;
765 #elif optional_CONFIG_MAX_ALIGN_HACK
767 typedef struct { unsigned char data[ sizeof(value_type) ]; } aligned_storage_t;
770 aligned_storage_t data;
773 typedef optional_ALIGN_AS(value_type) align_as_type;
775 typedef struct { align_as_type data[ 1 + ( sizeof(value_type) - 1 ) / sizeof(align_as_type) ]; } aligned_storage_t;
776 aligned_storage_t data;
778 # undef optional_ALIGN_AS
780 #endif // optional_CONFIG_MAX_ALIGN_HACK
782 optional_nodiscard void * ptr() optional_noexcept
787 optional_nodiscard void const * ptr() const optional_noexcept
792 template <typename U>
793 optional_nodiscard U * as()
795 return reinterpret_cast<U*>( ptr() );
798 template <typename U>
799 optional_nodiscard U const * as() const
801 return reinterpret_cast<U const *>( ptr() );
805 } // namespace detail
807 /// disengaged state tag
812 explicit optional_constexpr nullopt_t( init /*unused*/ ) optional_noexcept {}
815 #if optional_HAVE( CONSTEXPR_11 )
816 constexpr nullopt_t nullopt{ nullopt_t::init{} };
818 // extra parenthesis to prevent the most vexing parse:
819 const nullopt_t nullopt(( nullopt_t::init() ));
822 /// optional access error
824 #if ! optional_CONFIG_NO_EXCEPTIONS
826 class bad_optional_access : public std::logic_error
829 explicit bad_optional_access()
830 : logic_error( "bad optional access" ) {}
833 #endif //optional_CONFIG_NO_EXCEPTIONS
837 template< typename T>
841 template< typename > friend class optional;
843 typedef void (optional::*safe_bool)() const;
846 typedef T value_type;
848 // x.x.3.1, constructors
850 // 1a - default construct
851 optional_constexpr optional() optional_noexcept
852 : has_value_( false )
856 // 1b - construct explicitly empty
857 // NOLINTNEXTLINE( google-explicit-constructor, hicpp-explicit-conversions )
858 optional_constexpr optional( nullopt_t /*unused*/ ) optional_noexcept
859 : has_value_( false )
863 // 2 - copy-construct
864 optional_constexpr14 optional( optional const & other
865 #if optional_CPP11_OR_GREATER
867 true || std::is_copy_constructible<T>::value
871 : has_value_( other.has_value() )
873 if ( other.has_value() )
875 contained.construct_value( other.contained.value() );
879 #if optional_CPP11_OR_GREATER
881 // 3 (C++11) - move-construct from optional
882 optional_constexpr14 optional( optional && other
884 true || std::is_move_constructible<T>::value
886 // NOLINTNEXTLINE( performance-noexcept-move-constructor )
887 ) noexcept( std::is_nothrow_move_constructible<T>::value )
888 : has_value_( other.has_value() )
890 if ( other.has_value() )
892 contained.construct_value( std::move( other.contained.value() ) );
896 // 4a (C++11) - explicit converting copy-construct from optional
897 template< typename U >
898 explicit optional( optional<U> const & other
900 std::is_constructible<T, U const &>::value
901 && !std::is_constructible<T, optional<U> & >::value
902 && !std::is_constructible<T, optional<U> && >::value
903 && !std::is_constructible<T, optional<U> const & >::value
904 && !std::is_constructible<T, optional<U> const && >::value
905 && !std::is_convertible< optional<U> & , T>::value
906 && !std::is_convertible< optional<U> && , T>::value
907 && !std::is_convertible< optional<U> const & , T>::value
908 && !std::is_convertible< optional<U> const &&, T>::value
909 && !std::is_convertible< U const & , T>::value /*=> explicit */
912 : has_value_( other.has_value() )
914 if ( other.has_value() )
916 contained.construct_value( T{ other.contained.value() } );
919 #endif // optional_CPP11_OR_GREATER
921 // 4b (C++98 and later) - non-explicit converting copy-construct from optional
922 template< typename U >
923 // NOLINTNEXTLINE( google-explicit-constructor, hicpp-explicit-conversions )
924 optional( optional<U> const & other
925 #if optional_CPP11_OR_GREATER
927 std::is_constructible<T, U const &>::value
928 && !std::is_constructible<T, optional<U> & >::value
929 && !std::is_constructible<T, optional<U> && >::value
930 && !std::is_constructible<T, optional<U> const & >::value
931 && !std::is_constructible<T, optional<U> const && >::value
932 && !std::is_convertible< optional<U> & , T>::value
933 && !std::is_convertible< optional<U> && , T>::value
934 && !std::is_convertible< optional<U> const & , T>::value
935 && !std::is_convertible< optional<U> const &&, T>::value
936 && std::is_convertible< U const & , T>::value /*=> non-explicit */
938 #endif // optional_CPP11_OR_GREATER
940 : has_value_( other.has_value() )
942 if ( other.has_value() )
944 contained.construct_value( other.contained.value() );
948 #if optional_CPP11_OR_GREATER
950 // 5a (C++11) - explicit converting move-construct from optional
951 template< typename U >
952 explicit optional( optional<U> && other
954 std::is_constructible<T, U &&>::value
955 && !std::is_constructible<T, optional<U> & >::value
956 && !std::is_constructible<T, optional<U> && >::value
957 && !std::is_constructible<T, optional<U> const & >::value
958 && !std::is_constructible<T, optional<U> const && >::value
959 && !std::is_convertible< optional<U> & , T>::value
960 && !std::is_convertible< optional<U> && , T>::value
961 && !std::is_convertible< optional<U> const & , T>::value
962 && !std::is_convertible< optional<U> const &&, T>::value
963 && !std::is_convertible< U &&, T>::value /*=> explicit */
966 : has_value_( other.has_value() )
968 if ( other.has_value() )
970 contained.construct_value( T{ std::move( other.contained.value() ) } );
974 // 5a (C++11) - non-explicit converting move-construct from optional
975 template< typename U >
976 // NOLINTNEXTLINE( google-explicit-constructor, hicpp-explicit-conversions )
977 optional( optional<U> && other
979 std::is_constructible<T, U &&>::value
980 && !std::is_constructible<T, optional<U> & >::value
981 && !std::is_constructible<T, optional<U> && >::value
982 && !std::is_constructible<T, optional<U> const & >::value
983 && !std::is_constructible<T, optional<U> const && >::value
984 && !std::is_convertible< optional<U> & , T>::value
985 && !std::is_convertible< optional<U> && , T>::value
986 && !std::is_convertible< optional<U> const & , T>::value
987 && !std::is_convertible< optional<U> const &&, T>::value
988 && std::is_convertible< U &&, T>::value /*=> non-explicit */
991 : has_value_( other.has_value() )
993 if ( other.has_value() )
995 contained.construct_value( std::move( other.contained.value() ) );
999 // 6 (C++11) - in-place construct
1000 template< typename... Args
1001 optional_REQUIRES_T(
1002 std::is_constructible<T, Args&&...>::value
1005 optional_constexpr explicit optional( nonstd_lite_in_place_t(T), Args&&... args )
1006 : has_value_( true )
1007 , contained( T( std::forward<Args>(args)...) )
1010 // 7 (C++11) - in-place construct, initializer-list
1011 template< typename U, typename... Args
1012 optional_REQUIRES_T(
1013 std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value
1016 optional_constexpr explicit optional( nonstd_lite_in_place_t(T), std::initializer_list<U> il, Args&&... args )
1017 : has_value_( true )
1018 , contained( T( il, std::forward<Args>(args)...) )
1021 // 8a (C++11) - explicit move construct from value
1022 template< typename U = value_type >
1023 optional_constexpr explicit optional( U && value
1024 optional_REQUIRES_A(
1025 std::is_constructible<T, U&&>::value
1026 && !std::is_same<typename std20::remove_cvref<U>::type, nonstd_lite_in_place_t(U)>::value
1027 && !std::is_same<typename std20::remove_cvref<U>::type, optional<T>>::value
1028 && !std::is_convertible<U&&, T>::value /*=> explicit */
1031 : has_value_( true )
1032 , contained( T{ std::forward<U>( value ) } )
1035 // 8b (C++11) - non-explicit move construct from value
1036 template< typename U = value_type >
1037 // NOLINTNEXTLINE( google-explicit-constructor, hicpp-explicit-conversions )
1038 optional_constexpr optional( U && value
1039 optional_REQUIRES_A(
1040 std::is_constructible<T, U&&>::value
1041 && !std::is_same<typename std20::remove_cvref<U>::type, nonstd_lite_in_place_t(U)>::value
1042 && !std::is_same<typename std20::remove_cvref<U>::type, optional<T>>::value
1043 && std::is_convertible<U&&, T>::value /*=> non-explicit */
1046 : has_value_( true )
1047 , contained( std::forward<U>( value ) )
1050 #else // optional_CPP11_OR_GREATER
1053 optional( value_type const & value )
1054 : has_value_( true )
1055 , contained( value )
1058 #endif // optional_CPP11_OR_GREATER
1060 // x.x.3.2, destructor
1066 contained.destruct_value();
1070 // x.x.3.3, assignment
1072 // 1 (C++98and later) - assign explicitly empty
1073 optional & operator=( nullopt_t /*unused*/) optional_noexcept
1079 // 2 (C++98and later) - copy-assign from optional
1080 #if optional_CPP11_OR_GREATER
1081 // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, misc-unconventional-assign-operator )
1082 optional_REQUIRES_R(
1085 // std::is_copy_constructible<T>::value
1086 // && std::is_copy_assignable<T>::value
1088 operator=( optional const & other )
1090 std::is_nothrow_move_assignable<T>::value
1091 && std::is_nothrow_move_constructible<T>::value
1094 optional & operator=( optional const & other )
1097 if ( (has_value() == true ) && (other.has_value() == false) ) { reset(); }
1098 else if ( (has_value() == false) && (other.has_value() == true ) ) { initialize( *other ); }
1099 else if ( (has_value() == true ) && (other.has_value() == true ) ) { contained.value() = *other; }
1103 #if optional_CPP11_OR_GREATER
1105 // 3 (C++11) - move-assign from optional
1106 // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, misc-unconventional-assign-operator )
1107 optional_REQUIRES_R(
1110 // std::is_move_constructible<T>::value
1111 // && std::is_move_assignable<T>::value
1113 operator=( optional && other ) noexcept
1115 if ( (has_value() == true ) && (other.has_value() == false) ) { reset(); }
1116 else if ( (has_value() == false) && (other.has_value() == true ) ) { initialize( std::move( *other ) ); }
1117 else if ( (has_value() == true ) && (other.has_value() == true ) ) { contained.value() = std::move( *other ); }
1121 // 4 (C++11) - move-assign from value
1122 template< typename U = T >
1123 // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, misc-unconventional-assign-operator )
1124 optional_REQUIRES_R(
1126 std::is_constructible<T , U>::value
1127 && std::is_assignable<T&, U>::value
1128 && !std::is_same<typename std20::remove_cvref<U>::type, nonstd_lite_in_place_t(U)>::value
1129 && !std::is_same<typename std20::remove_cvref<U>::type, optional<T>>::value
1130 && !(std::is_scalar<T>::value && std::is_same<T, typename std::decay<U>::type>::value)
1132 operator=( U && value )
1136 contained.value() = std::forward<U>( value );
1140 initialize( T( std::forward<U>( value ) ) );
1145 #else // optional_CPP11_OR_GREATER
1147 // 4 (C++98) - copy-assign from value
1148 template< typename U /*= T*/ >
1149 optional & operator=( U const & value )
1151 if ( has_value() ) contained.value() = value;
1152 else initialize( T( value ) );
1156 #endif // optional_CPP11_OR_GREATER
1158 // 5 (C++98 and later) - converting copy-assign from optional
1159 template< typename U >
1160 #if optional_CPP11_OR_GREATER
1161 // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, misc-unconventional-assign-operator )
1162 optional_REQUIRES_R(
1164 std::is_constructible< T , U const &>::value
1165 && std::is_assignable< T&, U const &>::value
1166 && !std::is_constructible<T, optional<U> & >::value
1167 && !std::is_constructible<T, optional<U> && >::value
1168 && !std::is_constructible<T, optional<U> const & >::value
1169 && !std::is_constructible<T, optional<U> const && >::value
1170 && !std::is_convertible< optional<U> & , T>::value
1171 && !std::is_convertible< optional<U> && , T>::value
1172 && !std::is_convertible< optional<U> const & , T>::value
1173 && !std::is_convertible< optional<U> const &&, T>::value
1174 && !std::is_assignable< T&, optional<U> & >::value
1175 && !std::is_assignable< T&, optional<U> && >::value
1176 && !std::is_assignable< T&, optional<U> const & >::value
1177 && !std::is_assignable< T&, optional<U> const && >::value
1181 #endif // optional_CPP11_OR_GREATER
1182 operator=( optional<U> const & other )
1184 return *this = optional( other );
1187 #if optional_CPP11_OR_GREATER
1189 // 6 (C++11) - converting move-assign from optional
1190 template< typename U >
1191 // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, misc-unconventional-assign-operator )
1192 optional_REQUIRES_R(
1194 std::is_constructible< T , U>::value
1195 && std::is_assignable< T&, U>::value
1196 && !std::is_constructible<T, optional<U> & >::value
1197 && !std::is_constructible<T, optional<U> && >::value
1198 && !std::is_constructible<T, optional<U> const & >::value
1199 && !std::is_constructible<T, optional<U> const && >::value
1200 && !std::is_convertible< optional<U> & , T>::value
1201 && !std::is_convertible< optional<U> && , T>::value
1202 && !std::is_convertible< optional<U> const & , T>::value
1203 && !std::is_convertible< optional<U> const &&, T>::value
1204 && !std::is_assignable< T&, optional<U> & >::value
1205 && !std::is_assignable< T&, optional<U> && >::value
1206 && !std::is_assignable< T&, optional<U> const & >::value
1207 && !std::is_assignable< T&, optional<U> const && >::value
1209 operator=( optional<U> && other )
1211 return *this = optional( std::move( other ) );
1214 // 7 (C++11) - emplace
1215 template< typename... Args
1216 optional_REQUIRES_T(
1217 std::is_constructible<T, Args&&...>::value
1220 T& emplace( Args&&... args )
1223 contained.emplace( std::forward<Args>(args)... );
1225 return contained.value();
1228 // 8 (C++11) - emplace, initializer-list
1229 template< typename U, typename... Args
1230 optional_REQUIRES_T(
1231 std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value
1234 T& emplace( std::initializer_list<U> il, Args&&... args )
1237 contained.emplace( il, std::forward<Args>(args)... );
1239 return contained.value();
1242 #endif // optional_CPP11_OR_GREATER
1246 void swap( optional & other )
1247 #if optional_CPP11_OR_GREATER
1249 std::is_nothrow_move_constructible<T>::value
1250 && std17::is_nothrow_swappable<T>::value
1255 if ( (has_value() == true ) && (other.has_value() == true ) ) { swap( **this, *other ); }
1256 else if ( (has_value() == false) && (other.has_value() == true ) ) { initialize( std11::move(*other) ); other.reset(); }
1257 else if ( (has_value() == true ) && (other.has_value() == false) ) { other.initialize( std11::move(**this) ); reset(); }
1260 // x.x.3.5, observers
1262 optional_constexpr value_type const * operator ->() const
1264 return assert( has_value() ),
1265 contained.value_ptr();
1268 optional_constexpr14 value_type * operator ->()
1270 return assert( has_value() ),
1271 contained.value_ptr();
1274 optional_constexpr value_type const & operator *() const optional_ref_qual
1276 return assert( has_value() ),
1280 optional_constexpr14 value_type & operator *() optional_ref_qual
1282 return assert( has_value() ),
1286 #if optional_HAVE( REF_QUALIFIER ) && ( !optional_COMPILER_GNUC_VERSION || optional_COMPILER_GNUC_VERSION >= 490 )
1288 optional_constexpr value_type const && operator *() const optional_refref_qual
1290 return std::move( **this );
1293 optional_constexpr14 value_type && operator *() optional_refref_qual
1295 return std::move( **this );
1300 #if optional_CPP11_OR_GREATER
1301 optional_constexpr explicit operator bool() const optional_noexcept
1306 optional_constexpr operator safe_bool() const optional_noexcept
1308 return has_value() ? &optional::this_type_does_not_support_comparisons : 0;
1312 // NOLINTNEXTLINE( modernize-use-nodiscard )
1313 /*optional_nodiscard*/ optional_constexpr bool has_value() const optional_noexcept
1318 // NOLINTNEXTLINE( modernize-use-nodiscard )
1319 /*optional_nodiscard*/ optional_constexpr14 value_type const & value() const optional_ref_qual
1321 #if optional_CONFIG_NO_EXCEPTIONS
1322 assert( has_value() );
1324 if ( ! has_value() )
1326 throw bad_optional_access();
1329 return contained.value();
1332 optional_constexpr14 value_type & value() optional_ref_qual
1334 #if optional_CONFIG_NO_EXCEPTIONS
1335 assert( has_value() );
1337 if ( ! has_value() )
1339 throw bad_optional_access();
1342 return contained.value();
1345 #if optional_HAVE( REF_QUALIFIER ) && ( !optional_COMPILER_GNUC_VERSION || optional_COMPILER_GNUC_VERSION >= 490 )
1347 // NOLINTNEXTLINE( modernize-use-nodiscard )
1348 /*optional_nodiscard*/ optional_constexpr value_type const && value() const optional_refref_qual
1350 return std::move( value() );
1353 optional_constexpr14 value_type && value() optional_refref_qual
1355 return std::move( value() );
1360 #if optional_CPP11_OR_GREATER
1362 template< typename U >
1363 optional_constexpr value_type value_or( U && v ) const optional_ref_qual
1365 return has_value() ? contained.value() : static_cast<T>(std::forward<U>( v ) );
1368 template< typename U >
1369 optional_constexpr14 value_type value_or( U && v ) optional_refref_qual
1371 return has_value() ? std::move( contained.value() ) : static_cast<T>(std::forward<U>( v ) );
1376 template< typename U >
1377 optional_constexpr value_type value_or( U const & v ) const
1379 return has_value() ? contained.value() : static_cast<value_type>( v );
1382 #endif // optional_CPP11_OR_GREATER
1384 // x.x.3.6, modifiers
1386 void reset() optional_noexcept
1390 contained.destruct_value();
1397 void this_type_does_not_support_comparisons() const {}
1399 template< typename V >
1400 void initialize( V const & value )
1402 assert( ! has_value() );
1403 contained.construct_value( value );
1407 #if optional_CPP11_OR_GREATER
1408 template< typename V >
1409 void initialize( V && value )
1411 assert( ! has_value() );
1412 contained.construct_value( std::move( value ) );
1420 detail::storage_t< value_type > contained;
1424 // Relational operators
1426 template< typename T, typename U >
1427 inline optional_constexpr bool operator==( optional<T> const & x, optional<U> const & y )
1429 return bool(x) != bool(y) ? false : !bool( x ) ? true : *x == *y;
1432 template< typename T, typename U >
1433 inline optional_constexpr bool operator!=( optional<T> const & x, optional<U> const & y )
1438 template< typename T, typename U >
1439 inline optional_constexpr bool operator<( optional<T> const & x, optional<U> const & y )
1441 return (!y) ? false : (!x) ? true : *x < *y;
1444 template< typename T, typename U >
1445 inline optional_constexpr bool operator>( optional<T> const & x, optional<U> const & y )
1450 template< typename T, typename U >
1451 inline optional_constexpr bool operator<=( optional<T> const & x, optional<U> const & y )
1456 template< typename T, typename U >
1457 inline optional_constexpr bool operator>=( optional<T> const & x, optional<U> const & y )
1462 // Comparison with nullopt
1464 template< typename T >
1465 inline optional_constexpr bool operator==( optional<T> const & x, nullopt_t /*unused*/ ) optional_noexcept
1470 template< typename T >
1471 inline optional_constexpr bool operator==( nullopt_t /*unused*/, optional<T> const & x ) optional_noexcept
1476 template< typename T >
1477 inline optional_constexpr bool operator!=( optional<T> const & x, nullopt_t /*unused*/ ) optional_noexcept
1482 template< typename T >
1483 inline optional_constexpr bool operator!=( nullopt_t /*unused*/, optional<T> const & x ) optional_noexcept
1488 template< typename T >
1489 inline optional_constexpr bool operator<( optional<T> const & /*unused*/, nullopt_t /*unused*/ ) optional_noexcept
1494 template< typename T >
1495 inline optional_constexpr bool operator<( nullopt_t /*unused*/, optional<T> const & x ) optional_noexcept
1500 template< typename T >
1501 inline optional_constexpr bool operator<=( optional<T> const & x, nullopt_t /*unused*/ ) optional_noexcept
1506 template< typename T >
1507 inline optional_constexpr bool operator<=( nullopt_t /*unused*/, optional<T> const & /*unused*/ ) optional_noexcept
1512 template< typename T >
1513 inline optional_constexpr bool operator>( optional<T> const & x, nullopt_t /*unused*/ ) optional_noexcept
1518 template< typename T >
1519 inline optional_constexpr bool operator>( nullopt_t /*unused*/, optional<T> const & /*unused*/ ) optional_noexcept
1524 template< typename T >
1525 inline optional_constexpr bool operator>=( optional<T> const & /*unused*/, nullopt_t /*unused*/ ) optional_noexcept
1530 template< typename T >
1531 inline optional_constexpr bool operator>=( nullopt_t /*unused*/, optional<T> const & x ) optional_noexcept
1536 // Comparison with T
1538 template< typename T, typename U >
1539 inline optional_constexpr bool operator==( optional<T> const & x, U const & v )
1541 return bool(x) ? *x == v : false;
1544 template< typename T, typename U >
1545 inline optional_constexpr bool operator==( U const & v, optional<T> const & x )
1547 return bool(x) ? v == *x : false;
1550 template< typename T, typename U >
1551 inline optional_constexpr bool operator!=( optional<T> const & x, U const & v )
1553 return bool(x) ? *x != v : true;
1556 template< typename T, typename U >
1557 inline optional_constexpr bool operator!=( U const & v, optional<T> const & x )
1559 return bool(x) ? v != *x : true;
1562 template< typename T, typename U >
1563 inline optional_constexpr bool operator<( optional<T> const & x, U const & v )
1565 return bool(x) ? *x < v : true;
1568 template< typename T, typename U >
1569 inline optional_constexpr bool operator<( U const & v, optional<T> const & x )
1571 return bool(x) ? v < *x : false;
1574 template< typename T, typename U >
1575 inline optional_constexpr bool operator<=( optional<T> const & x, U const & v )
1577 return bool(x) ? *x <= v : true;
1580 template< typename T, typename U >
1581 inline optional_constexpr bool operator<=( U const & v, optional<T> const & x )
1583 return bool(x) ? v <= *x : false;
1586 template< typename T, typename U >
1587 inline optional_constexpr bool operator>( optional<T> const & x, U const & v )
1589 return bool(x) ? *x > v : false;
1592 template< typename T, typename U >
1593 inline optional_constexpr bool operator>( U const & v, optional<T> const & x )
1595 return bool(x) ? v > *x : true;
1598 template< typename T, typename U >
1599 inline optional_constexpr bool operator>=( optional<T> const & x, U const & v )
1601 return bool(x) ? *x >= v : false;
1604 template< typename T, typename U >
1605 inline optional_constexpr bool operator>=( U const & v, optional<T> const & x )
1607 return bool(x) ? v >= *x : true;
1610 // Specialized algorithms
1612 template< typename T
1613 #if optional_CPP11_OR_GREATER
1614 optional_REQUIRES_T(
1615 std::is_move_constructible<T>::value
1616 && std17::is_swappable<T>::value )
1619 void swap( optional<T> & x, optional<T> & y )
1620 #if optional_CPP11_OR_GREATER
1621 noexcept( noexcept( x.swap(y) ) )
1627 #if optional_CPP11_OR_GREATER
1629 template< typename T >
1630 optional_constexpr optional< typename std::decay<T>::type > make_optional( T && value )
1632 return optional< typename std::decay<T>::type >( std::forward<T>( value ) );
1635 template< typename T, typename...Args >
1636 optional_constexpr optional<T> make_optional( Args&&... args )
1638 return optional<T>( nonstd_lite_in_place(T), std::forward<Args>(args)...);
1641 template< typename T, typename U, typename... Args >
1642 optional_constexpr optional<T> make_optional( std::initializer_list<U> il, Args&&... args )
1644 return optional<T>( nonstd_lite_in_place(T), il, std::forward<Args>(args)...);
1649 template< typename T >
1650 optional<T> make_optional( T const & value )
1652 return optional<T>( value );
1655 #endif // optional_CPP11_OR_GREATER
1657 } // namespace optional_lite
1659 using optional_lite::optional;
1660 using optional_lite::nullopt_t;
1661 using optional_lite::nullopt;
1662 using optional_lite::bad_optional_access;
1664 using optional_lite::make_optional;
1666 } // namespace nonstd
1668 #if optional_CPP11_OR_GREATER
1670 // specialize the std::hash algorithm:
1675 struct hash< nonstd::optional<T> >
1678 std::size_t operator()( nonstd::optional<T> const & v ) const optional_noexcept
1680 return bool( v ) ? std::hash<T>{}( *v ) : 0;
1686 #endif // optional_CPP11_OR_GREATER
1688 #if defined(__clang__)
1689 # pragma clang diagnostic pop
1690 #elif defined(__GNUC__)
1691 # pragma GCC diagnostic pop
1692 #elif defined(_MSC_VER )
1693 # pragma warning( pop )
1696 #endif // optional_USES_STD_OPTIONAL
1698 #endif // NONSTD_OPTIONAL_LITE_HPP