2017-09-29 19:45:17 +01:00
///
// optional - An implementation of std::optional with extensions
// Written in 2017 by Simon Brand (@TartanLlama)
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to the
// public domain worldwide. This software is distributed without any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
2017-10-02 08:58:09 +01:00
// along with this software. If not, see
// <http://creativecommons.org/publicdomain/zero/1.0/>.
2017-09-29 19:45:17 +01:00
///
2017-10-02 08:58:09 +01:00
# include <exception>
# include <functional>
# include <new>
2017-09-29 19:45:17 +01:00
# include <type_traits>
2017-10-01 14:54:19 +01:00
# include <utility>
2017-09-29 19:45:17 +01:00
2017-10-17 11:54:57 +01:00
# if __cplusplus == 201103L || _MSC_VER == 1900
2017-10-21 09:33:16 +01:00
/// \exclude
2017-10-02 20:18:40 +01:00
# define TL_OPTIONAL_11_CONSTEXPR
# else
2017-10-21 09:33:16 +01:00
/// \exclude
2017-10-02 20:18:40 +01:00
# define TL_OPTIONAL_11_CONSTEXPR constexpr
# endif
2017-10-17 11:54:57 +01:00
# if _MSC_VER == 1900
2017-10-21 09:33:16 +01:00
/// \exclude
2017-10-17 11:54:57 +01:00
# define TL_OPTIONAL_MSVC_2015_CONSTEXPR
# else
2017-10-21 09:33:16 +01:00
/// \exclude
2017-10-17 11:54:57 +01:00
# define TL_OPTIONAL_MSVC_2015_CONSTEXPR constexpr
# endif
2017-09-29 19:45:17 +01:00
namespace tl {
2017-10-21 19:04:41 +01:00
/// \brief Used to represent an optional with no data; essentially a bool
2017-10-02 12:03:52 +01:00
class monostate { } ;
2017-10-21 09:33:16 +01:00
/// \brief A tag type to tell optional to construct its value in-place
struct in_place_t {
explicit in_place_t ( ) = default ;
} ;
/// \brief A tag to tell optional to construct its value in-place
static constexpr in_place_t in_place { } ;
template < class T > class optional ;
/// \exclude
2017-10-02 08:58:09 +01:00
namespace detail {
template < class T > using remove_cv_t = typename std : : remove_cv < T > : : type ;
template < class T > using remove_const_t = typename std : : remove_const < T > : : type ;
template < class T >
using remove_volatile_t = typename std : : remove_volatile < T > : : type ;
template < class T > using add_cv_t = typename std : : add_cv < T > : : type ;
template < class T > using add_const_t = typename std : : add_const < T > : : type ;
template < class T > using add_volatile_t = typename std : : add_volatile < T > : : type ;
template < class T >
using remove_reference_t = typename std : : remove_reference < T > : : type ;
template < class T >
using add_lvalue_reference_t = typename std : : add_lvalue_reference < T > : : type ;
template < class T >
using add_rvalue_reference_t = typename std : : add_rvalue_reference < T > : : type ;
template < class T >
using remove_pointer_t = typename std : : remove_pointer < T > : : type ;
template < class T > using add_pointer_t = typename std : : add_pointer < T > : : type ;
template < class T > using make_signed_t = typename std : : make_signed < T > : : type ;
template < class T > using make_unsigned_t = typename std : : make_unsigned < T > : : type ;
template < class T > using remove_extent_t = typename std : : remove_extent < T > : : type ;
template < class T >
using remove_all_extents_t = typename std : : remove_all_extents < T > : : type ;
template < std : : size_t N , std : : size_t A = N >
using aligned_storage_t = typename std : : aligned_storage < N , A > : : type ;
template < std : : size_t N , class . . . Ts >
using aligned_union_t = typename std : : aligned_union < N , Ts . . . > : : type ;
template < class T > using decay_t = typename std : : decay < T > : : type ;
template < bool E , class T = void >
using enable_if_t = typename std : : enable_if < E , T > : : type ;
template < bool B , class T , class F >
using conditional_t = typename std : : conditional < B , T , F > : : type ;
template < class . . . Ts >
using common_type_t = typename std : : common_type < Ts . . . > : : type ;
template < class T >
using underlying_type_t = typename std : : underlying_type < T > : : type ;
template < class T > using result_of_t = typename std : : result_of < T > : : type ;
2017-10-01 14:54:19 +01:00
2017-10-02 08:58:09 +01:00
template < class . . . > struct conjunction : std : : true_type { } ;
template < class B > struct conjunction < B > : B { } ;
template < class B , class . . . Bs >
struct conjunction < B , Bs . . . >
: std : : conditional < bool ( B : : value ) , conjunction < Bs . . . > , B > : : type { } ;
2017-10-01 19:27:37 +01:00
2017-10-02 08:58:09 +01:00
template < class . . . > struct voider { using type = void ; } ;
template < class . . . Ts > using void_t = typename voider < Ts . . . > : : type ;
2017-10-02 12:03:52 +01:00
template < class T > struct is_optional_impl : std : : false_type { } ;
template < class T > struct is_optional_impl < optional < T > > : std : : true_type { } ;
template < class T > using is_optional = is_optional_impl < decay_t < T > > ;
// https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround
2017-10-17 13:08:31 +01:00
template < typename Fn , typename . . . Args ,
typename = enable_if_t < std : : is_member_pointer < decay_t < Fn > > { } > ,
int = 0 >
2017-10-02 12:03:52 +01:00
constexpr auto invoke ( Fn & & f , Args & & . . . args ) noexcept (
noexcept ( std : : mem_fn ( f ) ( std : : forward < Args > ( args ) . . . ) ) )
- > decltype ( std : : mem_fn ( f ) ( std : : forward < Args > ( args ) . . . ) ) {
return std : : mem_fn ( f ) ( std : : forward < Args > ( args ) . . . ) ;
}
2017-10-17 13:08:31 +01:00
template < typename Fn , typename . . . Args ,
typename = enable_if_t < ! std : : is_member_pointer < decay_t < Fn > > { } > >
2017-10-02 12:03:52 +01:00
constexpr auto invoke ( Fn & & f , Args & & . . . args ) noexcept (
noexcept ( std : : forward < Fn > ( f ) ( std : : forward < Args > ( args ) . . . ) ) )
- > decltype ( std : : forward < Fn > ( f ) ( std : : forward < Args > ( args ) . . . ) ) {
return std : : forward < Fn > ( f ) ( std : : forward < Args > ( args ) . . . ) ;
}
template < class F , class , class . . . Us > struct invoke_result_impl ;
template < class F , class . . . Us >
struct invoke_result_impl <
F , decltype ( invoke ( std : : declval < F > ( ) , std : : declval < Us > ( ) . . . ) , void ( ) ) ,
Us . . . > {
using type = decltype ( invoke ( std : : declval < F > ( ) , std : : declval < Us > ( ) . . . ) ) ;
} ;
template < class F , class . . . Us >
using invoke_result = invoke_result_impl < F , void , Us . . . > ;
template < class F , class . . . Us >
using invoke_result_t = typename invoke_result < F , Us . . . > : : type ;
template < class U >
2017-10-02 14:00:56 +01:00
using fixup_void = conditional_t < std : : is_void < U > : : value , monostate , U > ;
2017-10-02 12:03:52 +01:00
2017-10-06 10:03:12 +01:00
template < class F , class . . . U > struct get_invoke_optional_ret {
2017-10-02 20:18:40 +01:00
using type = invoke_result_t <
2017-10-02 14:00:56 +01:00
conditional_t < std : : is_lvalue_reference < F > : : value ,
2017-10-02 20:18:40 +01:00
typename remove_reference_t < F > : : value_type & ,
2017-10-04 10:45:48 +01:00
typename remove_reference_t < F > : : value_type & & > ,
2017-10-06 10:03:12 +01:00
U . . . > ;
2017-10-02 12:03:52 +01:00
} ;
2017-10-06 10:03:12 +01:00
template < class F , class . . . U >
using get_invoke_ret = typename conditional_t < is_optional < F > : : value ,
get_invoke_optional_ret < F , U . . . > ,
invoke_result < F , U . . . > > : : type ;
2017-10-02 12:03:52 +01:00
template < class F , class U >
using get_map_return = optional < fixup_void < get_invoke_ret < F , U > > > ;
2017-10-06 10:03:12 +01:00
template < class F , class . . . U >
using returns_void = std : : is_void < get_invoke_ret < F , U . . . > > ;
2017-10-02 14:00:56 +01:00
template < class T >
using disable_if_optional = enable_if_t < ! is_optional < T > : : value > ;
template < class T >
using enable_if_optional = enable_if_t < is_optional < T > : : value > ;
2017-10-06 10:03:12 +01:00
template < class T , class . . . U >
using enable_if_ret_void = enable_if_t < returns_void < T & & , U . . . > : : value > ;
2017-10-02 14:00:56 +01:00
2017-10-06 10:03:12 +01:00
template < class T , class . . . U >
using disable_if_ret_void = enable_if_t < ! returns_void < T & & , U . . . > : : value > ;
2017-10-01 14:54:19 +01:00
2017-10-02 08:58:09 +01:00
template < class T , class U >
using enable_forward_value =
detail : : enable_if_t < std : : is_constructible < T , U & & > : : value & &
! std : : is_same < detail : : decay_t < U > , in_place_t > : : value & &
! std : : is_same < optional < T > , detail : : decay_t < U > > : : value > ;
2017-10-01 14:54:19 +01:00
2017-10-02 08:58:09 +01:00
template < class T , class U , class Other >
using enable_from_other = detail : : enable_if_t <
std : : is_constructible < T , Other > : : value & &
! std : : is_constructible < T , optional < U > & > : : value & &
! std : : is_constructible < T , optional < U > & & > : : value & &
! std : : is_constructible < T , const optional < U > & > : : value & &
! std : : is_constructible < T , const optional < U > & & > : : value & &
! std : : is_convertible < optional < U > & , T > : : value & &
! std : : is_convertible < optional < U > & & , T > : : value & &
! std : : is_convertible < const optional < U > & , T > : : value & &
! std : : is_convertible < const optional < U > & & , T > : : value > ;
2017-10-01 19:27:37 +01:00
2017-10-02 08:58:09 +01:00
template < class T , class U >
using enable_assign_forward = detail : : enable_if_t <
! std : : is_same < optional < T > , detail : : decay_t < U > > : : value & &
! detail : : conjunction < std : : is_scalar < T > ,
std : : is_same < T , detail : : decay_t < U > > > : : value & &
std : : is_constructible < T , U > : : value & & std : : is_assignable < T & , U > : : value > ;
2017-10-01 19:27:37 +01:00
2017-10-02 08:58:09 +01:00
template < class T , class U , class Other >
using enable_assign_from_other = detail : : enable_if_t <
std : : is_constructible < T , Other > : : value & &
std : : is_assignable < T & , Other > : : value & &
! std : : is_constructible < T , optional < U > & > : : value & &
! std : : is_constructible < T , optional < U > & & > : : value & &
! std : : is_constructible < T , const optional < U > & > : : value & &
! std : : is_constructible < T , const optional < U > & & > : : value & &
! std : : is_convertible < optional < U > & , T > : : value & &
! std : : is_convertible < optional < U > & & , T > : : value & &
! std : : is_convertible < const optional < U > & , T > : : value & &
! std : : is_convertible < const optional < U > & & , T > : : value & &
! std : : is_assignable < T & , optional < U > & > : : value & &
! std : : is_assignable < T & , optional < U > & & > : : value & &
! std : : is_assignable < T & , const optional < U > & > : : value & &
! std : : is_assignable < T & , const optional < U > & & > : : value > ;
2017-10-01 14:54:19 +01:00
2017-10-17 11:54:57 +01:00
# ifdef _MSC_VER
// TODO make a version which works with MSVC
template < class T , class U = T > struct is_swappable : std : : true_type { } ;
template < class T , class U = T > struct is_nothrow_swappable : std : : true_type { } ;
# else
2017-10-02 08:58:09 +01:00
// https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept
namespace swap_adl_tests {
// if swap ADL finds this then it would call std::swap otherwise (same
// signature)
struct tag { } ;
2017-10-01 14:54:19 +01:00
2017-10-02 08:58:09 +01:00
template < class T > tag swap ( T & , T & ) ;
template < class T , std : : size_t N > tag swap ( T ( & a ) [ N ] , T ( & b ) [ N ] ) ;
2017-10-01 14:54:19 +01:00
2017-10-02 08:58:09 +01:00
// helper functions to test if an unqualified swap is possible, and if it
// becomes std::swap
template < class , class > std : : false_type can_swap ( . . . ) noexcept ( false ) ;
template < class T , class U ,
class = decltype ( swap ( std : : declval < T & > ( ) , std : : declval < U & > ( ) ) ) >
std : : true_type can_swap ( int ) noexcept ( noexcept ( swap ( std : : declval < T & > ( ) ,
std : : declval < U & > ( ) ) ) ) ;
2017-10-01 14:54:19 +01:00
2017-10-02 08:58:09 +01:00
template < class , class > std : : false_type uses_std ( . . . ) ;
template < class T , class U >
std : : is_same < decltype ( swap ( std : : declval < T & > ( ) , std : : declval < U & > ( ) ) ) , tag >
uses_std ( int ) ;
2017-10-02 08:57:21 +01:00
2017-10-02 08:58:09 +01:00
template < class T >
struct is_std_swap_noexcept
: std : : integral_constant < bool ,
std : : is_nothrow_move_constructible < T > : : value & &
std : : is_nothrow_move_assignable < T > : : value > { } ;
2017-10-02 08:57:21 +01:00
2017-10-02 08:58:09 +01:00
template < class T , std : : size_t N >
struct is_std_swap_noexcept < T [ N ] > : is_std_swap_noexcept < T > { } ;
2017-10-02 08:57:21 +01:00
2017-10-02 08:58:09 +01:00
template < class T , class U >
struct is_adl_swap_noexcept
: std : : integral_constant < bool , noexcept ( can_swap < T , U > ( 0 ) ) > { } ;
2017-10-17 11:54:57 +01:00
} // namespace swap_adl_tests
2017-10-02 08:57:21 +01:00
2017-10-02 08:58:09 +01:00
template < class T , class U = T >
struct is_swappable
: std : : integral_constant <
bool ,
decltype ( detail : : swap_adl_tests : : can_swap < T , U > ( 0 ) ) : : value & &
( ! decltype ( detail : : swap_adl_tests : : uses_std < T , U > ( 0 ) ) : : value | |
( std : : is_move_assignable < T > : : value & &
std : : is_move_constructible < T > : : value ) ) > { } ;
2017-10-02 08:57:21 +01:00
2017-10-02 08:58:09 +01:00
template < class T , std : : size_t N >
struct is_swappable < T [ N ] , T [ N ] >
: std : : integral_constant <
bool ,
decltype ( detail : : swap_adl_tests : : can_swap < T [ N ] , T [ N ] > ( 0 ) ) : : value & &
( ! decltype (
detail : : swap_adl_tests : : uses_std < T [ N ] , T [ N ] > ( 0 ) ) : : value | |
is_swappable < T , T > : : value ) > { } ;
2017-10-02 08:57:21 +01:00
2017-10-02 08:58:09 +01:00
template < class T , class U = T >
struct is_nothrow_swappable
: std : : integral_constant <
bool ,
is_swappable < T , U > : : value & &
( ( decltype ( detail : : swap_adl_tests : : uses_std < T , U > ( 0 ) ) : : value
& & detail : : swap_adl_tests : : is_std_swap_noexcept < T > : : value ) | |
( ! decltype ( detail : : swap_adl_tests : : uses_std < T , U > ( 0 ) ) : : value & &
detail : : swap_adl_tests : : is_adl_swap_noexcept < T ,
U > : : value ) ) > {
} ;
2017-10-11 19:18:08 +01:00
# endif
2017-10-21 19:04:41 +01:00
template < class T , bool = : : std : : is_trivially_destructible < T > : : value >
struct optional_storage_base {
TL_OPTIONAL_MSVC_2015_CONSTEXPR optional_storage_base ( ) noexcept : m_dummy ( ) , m_has_value ( false ) { }
template < class . . . U >
TL_OPTIONAL_MSVC_2015_CONSTEXPR optional_storage_base ( in_place_t , U & & . . . u ) noexcept
: m_value ( std : : forward < U > ( u ) . . . ) , m_has_value ( true ) { }
~ optional_storage_base ( ) {
if ( m_has_value ) {
m_value . ~ T ( ) ;
m_has_value = false ;
}
}
struct dummy { } ;
union {
dummy m_dummy ;
T m_value ;
} ;
bool m_has_value ;
} ;
template < class T > struct optional_storage_base < T , true > {
TL_OPTIONAL_MSVC_2015_CONSTEXPR optional_storage_base ( ) noexcept
: m_dummy ( ) , m_has_value ( false ) { }
template < class . . . U >
TL_OPTIONAL_MSVC_2015_CONSTEXPR optional_storage_base ( in_place_t ,
U & & . . . u ) noexcept
: m_value ( std : : forward < U > ( u ) . . . ) , m_has_value ( true ) { }
~ optional_storage_base ( ) = default ;
struct dummy { } ;
union {
dummy m_dummy ;
T m_value ;
} ;
bool m_has_value = false ;
} ;
2017-10-17 11:54:57 +01:00
} // namespace detail
2017-10-02 08:57:21 +01:00
2017-10-21 09:33:16 +01:00
/// \brief A tag type to represent an empty optional
2017-10-02 08:58:09 +01:00
struct nullopt_t {
struct do_not_use { } ;
constexpr explicit nullopt_t ( do_not_use , do_not_use ) noexcept { }
} ;
2017-10-21 09:33:16 +01:00
/// \brief Represents an empty optional
/// \synopsis static constexpr nullopt_t nullopt;
///
/// *Examples*:
/// ```
/// tl::optional<int> a = tl::nullopt;
/// void foo (tl::optional<int>);
/// foo(tl::nullopt); //pass an empty optional
/// ```
2017-10-02 08:58:09 +01:00
static constexpr nullopt_t nullopt { nullopt_t : : do_not_use { } ,
nullopt_t : : do_not_use { } } ;
2017-10-01 14:54:19 +01:00
2017-10-02 08:58:09 +01:00
class bad_optional_access : public std : : exception {
public :
bad_optional_access ( ) = default ;
const char * what ( ) const noexcept { return " Optional has no value " ; }
} ;
2017-09-29 19:45:17 +01:00
2017-10-21 19:04:41 +01:00
/// An optional object is an object that contains the storage for another object and manages the lifetime of this contained object, if any. The contained object may be initialized after the optional object has been initialized, and may be destroyed before the optional object has been destroyed. The initialization state of the contained object is tracked by the optional object.
template < class T > class optional : private detail : : optional_storage_base < T > {
using base = detail : : optional_storage_base < T > ;
public :
/// \group and_then
/// Carries out some operation which returns an optional on the stored object if there is one.
/// \requires `std::invoke(std::forward<F>(f), value())` returns a `std::optional<U>` for some `U`.
/// \returns Let `U` be the result of `std::invoke(std::forward<F>(f), value())`. Returns a `std::optional<U>`. The return value is empty if `*this` is empty, otherwise the return value of `std::invoke(std::forward<F>(f), value())` is returned.
/// \group and_then
/// \synopsis template <class F> constexpr auto and_then(F &&f);
template < class F >
TL_OPTIONAL_11_CONSTEXPR detail : : invoke_result_t < F , T > and_then ( F & & f ) & {
using result = detail : : invoke_result_t < F , T > ;
static_assert ( detail : : is_optional < result > : : value ,
" F must return an optional " ) ;
return has_value ( ) ? detail : : invoke ( std : : forward < F > ( f ) , * * this )
: result ( nullopt ) ;
}
/// \exclude
template < class F >
TL_OPTIONAL_11_CONSTEXPR detail : : invoke_result_t < F , T > and_then ( F & & f ) & & {
using result = detail : : invoke_result_t < F , T > ;
static_assert ( detail : : is_optional < result > : : value ,
" F must return an optional " ) ;
return has_value ( ) ? detail : : invoke ( std : : forward < F > ( f ) , std : : move ( * * this ) )
: result ( nullopt ) ;
}
/// \group and_then
/// \synopsis template <class F> constexpr auto and_then(F &&f) const;
template < class F >
constexpr detail : : invoke_result_t < F , T > and_then ( F & & f ) const & {
using result = detail : : invoke_result_t < F , T > ;
static_assert ( detail : : is_optional < result > : : value ,
" F must return an optional " ) ;
return has_value ( ) ? detail : : invoke ( std : : forward < F > ( f ) , * * this )
: result ( nullopt ) ;
}
/// \exclude
template < class F >
constexpr detail : : invoke_result_t < F , T > and_then ( F & & f ) const & & {
using result = detail : : invoke_result_t < F , T > ;
static_assert ( detail : : is_optional < result > : : value ,
" F must return an optional " ) ;
return has_value ( ) ? detail : : invoke ( std : : forward < F > ( f ) , std : : move ( * * this ) )
: result ( nullopt ) ;
}
/// \brief Carries out some operation on the stored object if there is one.
/// \returns Let `U` be the result of `std::invoke(std::forward<F>(f), value())`. Returns a `std::optional<U>`. The return value is empty if `*this` is empty, otherwise an `optional<U>` is constructed from the return value of `std::invoke(std::forward<F>(f), value())` and is returned.
/// \group map
/// \synopsis template <class F> auto map(F &&f);
template < class F , detail : : disable_if_optional < F > * = nullptr ,
detail : : disable_if_ret_void < F , T & > * = nullptr >
detail : : get_map_return < F , T & > map ( F & & f ) &
noexcept ( noexcept ( detail : : invoke ( std : : forward < F > ( f ) ,
std : : declval < T & > ( ) ) ) ) {
using result = detail : : get_map_return < F , T & > ;
return has_value ( ) ? detail : : invoke ( std : : forward < F > ( f ) , * * this )
: result ( nullopt ) ;
}
/// \exclude
template < class F , detail : : disable_if_optional < F > * = nullptr ,
detail : : enable_if_ret_void < F , T & > * = nullptr >
detail : : get_map_return < F , T & > map ( F & & f ) & {
if ( ! has_value ( ) )
return nullopt ;
detail : : invoke ( std : : forward < F > ( f ) , * * this ) ;
return monostate { } ;
}
/// \exclude
template < class F , detail : : enable_if_optional < F > * = nullptr ,
detail : : disable_if_ret_void < F , T & > * = nullptr >
detail : : get_map_return < F , T & > map ( F & & f ) & {
using result = detail : : get_map_return < F , T & > ;
return ( f . has_value ( ) & & has_value ( ) )
? detail : : invoke ( * std : : forward < F > ( f ) , * * this )
: result ( nullopt ) ;
}
/// \exclude
template < class F , detail : : enable_if_optional < F > * = nullptr ,
detail : : enable_if_ret_void < F , T & > * = nullptr >
detail : : get_map_return < F , T & > map ( F & & f ) & {
if ( ! f . has_value ( ) | | ! has_value ( ) )
return nullopt ;
detail : : invoke ( * std : : forward < F > ( f ) , * * this ) ;
return monostate { } ;
}
/// \exclude
template < class F , detail : : disable_if_optional < F > * = nullptr ,
detail : : disable_if_ret_void < F , T & & > * = nullptr >
detail : : get_map_return < F , T & & > map ( F & & f ) & & {
using result = detail : : get_map_return < F , T & & > ;
return has_value ( ) ? detail : : invoke ( std : : forward < F > ( f ) , std : : move ( * * this ) )
: result ( nullopt ) ;
}
/// \exclude
template < class F , detail : : disable_if_optional < F > * = nullptr ,
detail : : enable_if_ret_void < F , T & & > * = nullptr >
detail : : get_map_return < F , T & & > map ( F & & f ) & & {
if ( ! has_value ( ) )
return nullopt ;
detail : : invoke ( std : : forward < F > ( f ) , std : : move ( * * this ) ) ;
return monostate { } ;
}
/// \exclude
template < class F , detail : : enable_if_optional < F > * = nullptr ,
detail : : disable_if_ret_void < F , T & & > * = nullptr >
detail : : get_map_return < F , T & & > map ( F & & f ) & & {
using result = detail : : get_map_return < F , T & & > ;
return ( f . has_value ( ) & & has_value ( ) )
? detail : : invoke ( * std : : forward < F > ( f ) , std : : move ( * * this ) )
: result ( nullopt ) ;
}
/// \exclude
template < class F , detail : : enable_if_optional < F > * = nullptr ,
detail : : enable_if_ret_void < F , T & & > * = nullptr >
detail : : get_map_return < F , T & & > map ( F & & f ) & & {
if ( ! f . has_value ( ) | | ! has_value ( ) )
return nullopt ;
detail : : invoke ( * std : : forward < F > ( f ) , std : : move ( * * this ) ) ;
return monostate { } ;
}
/// \group map
/// \synopsis template <class F> auto map(F &&f) const;
template < class F , detail : : disable_if_optional < F > * = nullptr ,
detail : : disable_if_ret_void < F , T const & > * = nullptr >
constexpr detail : : get_map_return < F , T const & > map ( F & & f ) const & {
using result = detail : : get_map_return < F , T const & > ;
return this - > has_value ( )
? result ( detail : : invoke ( std : : forward < F > ( f ) , * * this ) )
: result ( nullopt ) ;
}
/// \exclude
template < class F , detail : : disable_if_optional < F > * = nullptr ,
detail : : enable_if_ret_void < F , T const & > * = nullptr >
detail : : get_map_return < F , T const & > map ( F & & f ) const & {
if ( ! has_value ( ) )
return nullopt ;
detail : : invoke ( std : : forward < F > ( f ) , * * this ) ;
return monostate { } ;
}
/// \exclude
template < class F , detail : : enable_if_optional < F > * = nullptr ,
detail : : disable_if_ret_void < F , T const & > * = nullptr >
constexpr detail : : get_map_return < F , T const & > map ( F & & f ) const & {
using result = detail : : get_map_return < F , const T & > ;
return ( f . has_value ( ) & & has_value ( ) )
? detail : : invoke ( * std : : forward < F > ( f ) , * * this )
: result ( nullopt ) ;
}
/// \exclude
template < class F , detail : : enable_if_optional < F > * = nullptr ,
detail : : enable_if_ret_void < F , T const & > * = nullptr >
detail : : get_map_return < F , T const & > map ( F & & f ) const & {
if ( ! f . has_value ( ) | | ! has_value ( ) )
return nullopt ;
detail : : invoke ( * std : : forward < F > ( f ) , * * this ) ;
return monostate { } ;
}
/// \exclude
template < class F , detail : : disable_if_optional < F > * = nullptr ,
detail : : disable_if_ret_void < F , T const & & > * = nullptr >
constexpr detail : : get_map_return < F , T const & & > map ( F & & f ) const & & {
using result = detail : : get_map_return < F , const T & & > ;
return has_value ( ) ? detail : : invoke ( std : : forward < F > ( f ) , std : : move ( * * this ) )
: result ( nullopt ) ;
}
/// \exclude
template < class F , detail : : disable_if_optional < F > * = nullptr ,
detail : : enable_if_ret_void < F , T const & & > * = nullptr >
detail : : get_map_return < F , T const & & > map ( F & & f ) const & & {
if ( ! has_value ( ) )
return nullopt ;
detail : : invoke ( std : : forward < F > ( f ) , std : : move ( * * this ) ) ;
return monostate { } ;
}
/// \exclude
template < class F , detail : : enable_if_optional < F > * = nullptr ,
detail : : disable_if_ret_void < F , T const & & > * = nullptr >
constexpr detail : : get_map_return < F , T const & & > map ( F & & f ) const & & {
using result = detail : : get_map_return < F , const T & & > ;
return ( f . has_value ( ) & & has_value ( ) )
? detail : : invoke ( * std : : forward < F > ( f ) , std : : move ( * * this ) )
: result ( nullopt ) ;
}
/// \exclude
template < class F , detail : : enable_if_optional < F > * = nullptr ,
detail : : enable_if_ret_void < F , T const & & > * = nullptr >
detail : : get_map_return < F , T & > map ( F & & f ) const & & {
if ( ! f . has_value ( ) | | ! has_value ( ) )
return nullopt ;
detail : : invoke ( * std : : forward < F > ( f ) , std : : move ( * * this ) ) ;
return monostate { } ;
}
/// \brief Calls `f` if the optional is empty
/// \requires `std::invoke_result_t<F>` must be void or convertible to `optional<T>`.
/// \effects If `*this` has a value, returns `*this`. Otherwise, if `f` returns `void`, calls `std::forward<F>(f)` and returns `std::nullopt`. Otherwise, returns `std::forward<F>(f)()`.
/// \group or_else
/// \synopsis template <class F> optional<T> or_else (F &&f);
template < class F , detail : : enable_if_ret_void < F > * = nullptr >
optional < T > TL_OPTIONAL_MSVC_2015_CONSTEXPR or_else ( F & & f ) & {
if ( has_value ( ) )
return * this ;
std : : forward < F > ( f ) ( ) ;
return nullopt ;
}
/// \exclude
template < class F , detail : : disable_if_ret_void < F > * = nullptr >
optional < T > TL_OPTIONAL_MSVC_2015_CONSTEXPR or_else ( F & & f ) & {
return has_value ( ) ? * this : std : : forward < F > ( f ) ( ) ;
}
/// \exclude
template < class F , detail : : enable_if_ret_void < F > * = nullptr >
optional < T > or_else ( F & & f ) & & {
if ( has_value ( ) )
return std : : move ( * this ) ;
std : : forward < F > ( f ) ( ) ;
return nullopt ;
}
/// \exclude
template < class F , detail : : disable_if_ret_void < F > * = nullptr >
optional < T > TL_OPTIONAL_MSVC_2015_CONSTEXPR or_else ( F & & f ) & & {
return has_value ( ) ? std : : move ( * this ) : std : : forward < F > ( f ) ( ) ;
}
/// \exclude
template < class F , detail : : enable_if_ret_void < F > * = nullptr >
optional < T > or_else ( F & & f ) const & {
if ( has_value ( ) )
return * this ;
std : : forward < F > ( f ) ( ) ;
return nullopt ;
}
/// \group or_else
/// \synopsis template <class F> optional<T> or_else (F &&f) const;
template < class F , detail : : disable_if_ret_void < F > * = nullptr >
optional < T > TL_OPTIONAL_MSVC_2015_CONSTEXPR or_else ( F & & f ) const & {
return has_value ( ) ? * this : std : : forward < F > ( f ) ( ) ;
}
/// \exclude
template < class F , detail : : enable_if_ret_void < F > * = nullptr >
optional < T > or_else ( F & & f ) const & & {
if ( has_value ( ) )
return std : : move ( * this ) ;
std : : forward < F > ( f ) ( ) ;
return nullopt ;
}
/// \exclude
template < class F , detail : : disable_if_ret_void < F > * = nullptr >
optional < T > or_else ( F & & f ) const & & {
return has_value ( ) ? std : : move ( * this ) : std : : forward < F > ( f ) ( ) ;
}
/// \brief Maps the stored value with `f` if there is one, otherwise returns `u`
/// \details If there is a value stored, then `f` is called with `**this` and the value is returned.
/// Otherwise `u` is returned.
/// \group map_or
/// \synopsis template <class F, class U> U map_or(F &&f, U &&u);
template < class F , class U > U map_or ( F & & f , U & & u ) & {
return has_value ( ) ? detail : : invoke ( std : : forward < F > ( f ) , * * this )
: std : : forward < U > ( u ) ;
}
/// \exclude
template < class F , class U > U map_or ( F & & f , U & & u ) & & {
return has_value ( ) ? detail : : invoke ( std : : forward < F > ( f ) , std : : move ( * * this ) )
: std : : forward < U > ( u ) ;
}
/// \group map_or
/// \synopsis template <class F, class U> U map_or(F &&f, U &&u) const;
template < class F , class U > U map_or ( F & & f , U & & u ) const & {
return has_value ( ) ? detail : : invoke ( std : : forward < F > ( f ) , * * this )
: std : : forward < U > ( u ) ;
}
/// \exclude
template < class F , class U > U map_or ( F & & f , U & & u ) const & & {
return has_value ( ) ? detail : : invoke ( std : : forward < F > ( f ) , std : : move ( * * this ) )
: std : : forward < U > ( u ) ;
}
/// \brief Maps the stored value with `f` if there is one, otherwise calls `u` and returns the result.
/// \details If there is a value stored, then `f` is called with `**this` and the value is returned.
/// Otherwise `std::forward<U>(u)()` is returned.
/// \synopsis template <class F, class U> U map_or_else(F &&f, U &&u);
/// \group map_or_else
template < class F , class U > U map_or_else ( F & & f , U & & u ) & {
return has_value ( ) ? detail : : invoke ( std : : forward < F > ( f ) , * * this )
: std : : forward < U > ( u ) ( ) ;
}
/// \exclude
template < class F , class U > U map_or_else ( F & & f , U & & u ) & & {
return has_value ( ) ? detail : : invoke ( std : : forward < F > ( f ) , std : : move ( * * this ) )
: std : : forward < U > ( u ) ( ) ;
}
/// \group map_or_else
/// \synopsis template <class F, class U> U map_or_else(F &&f, U &&u) const;
template < class F , class U > U map_or_else ( F & & f , U & & u ) const & {
return has_value ( ) ? detail : : invoke ( std : : forward < F > ( f ) , * * this )
: std : : forward < U > ( u ) ( ) ;
}
/// \exclude
template < class F , class U > U map_or_else ( F & & f , U & & u ) const & & {
return has_value ( ) ? detail : : invoke ( std : : forward < F > ( f ) , std : : move ( * * this ) )
: std : : forward < U > ( u ) ( ) ;
}
using value_type = T ;
/// Constructs an optional that does not contain a value.
/// \group ctor_empty
constexpr optional ( ) noexcept = default ;
/// \group ctor_empty
constexpr optional ( nullopt_t ) noexcept { } ;
/// Copy constructor
///
/// If `rhs` contains a value, the stored value is direct-initialized with it.
/// Otherwise, the constructed optional is empty.
TL_OPTIONAL_11_CONSTEXPR optional ( const optional & rhs ) {
if ( rhs . has_value ( ) ) {
this - > m_has_value = true ;
new ( std : : addressof ( this - > m_value ) ) T ( * rhs ) ;
}
}
// TODO conditionally disable
/// Move constructor
///
/// If `rhs` contains a value, the stored value is direct-initialized with it.
/// Otherwise, the constructed optional is empty.
TL_OPTIONAL_11_CONSTEXPR optional ( optional & & rhs ) noexcept (
std : : is_nothrow_move_constructible < T > : : value ) {
if ( rhs . has_value ( ) ) {
this - > m_has_value = true ;
new ( std : : addressof ( this - > m_value ) ) T ( std : : move ( * rhs ) ) ;
}
}
/// Constructs the stored value in-place using the given arguments.
/// \group in_place
/// \synopsis template <class... Args> constexpr explicit optional(in_place_t, Args&&... args);
template < class . . . Args >
constexpr explicit optional (
detail : : enable_if_t < std : : is_constructible < T , Args . . . > : : value , in_place_t > ,
Args & & . . . args )
: base ( in_place , std : : forward < Args > ( args ) . . . ) { }
/// \group in_place
/// \synopsis template <class U, class... Args>\nconstexpr explicit optional(in_place_t, std::initializer_list<U>&, Args&&... args);
template < class U , class . . . Args >
TL_OPTIONAL_11_CONSTEXPR explicit optional (
detail : : enable_if_t < std : : is_constructible < T , std : : initializer_list < U > & ,
Args & & . . . > : : value ,
in_place_t > ,
std : : initializer_list < U > il , Args & & . . . args ) {
this - > m_has_value = true ;
new ( std : : addressof ( this - > m_value ) ) T ( il , std : : forward < Args > ( args ) . . . ) ;
}
/// Constructs the stored value with `u`.
/// \synopsis template <class U=T> constexpr optional(U &&u);
template <
class U = T ,
detail : : enable_if_t < std : : is_convertible < U & & , T > : : value > * = nullptr ,
detail : : enable_forward_value < T , U > * = nullptr >
constexpr optional ( U & & u ) : base ( in_place , std : : forward < U > ( u ) ) { }
/// \exclude
template <
class U = T ,
detail : : enable_if_t < ! std : : is_convertible < U & & , T > : : value > * = nullptr ,
detail : : enable_forward_value < T , U > * = nullptr >
constexpr explicit optional ( U & & u ) : base ( in_place , std : : forward < U > ( u ) ) { }
/// Converting copy constructor.
/// \synopsis template <class U> optional(const optional<U> &rhs);
template <
class U , detail : : enable_from_other < T , U , const U & > * = nullptr ,
detail : : enable_if_t < std : : is_convertible < const U & , T > : : value > * = nullptr >
optional ( const optional < U > & rhs ) {
this - > m_has_value = true ;
new ( std : : addressof ( this - > m_value ) ) T ( * rhs ) ;
}
/// \exclude
template < class U , detail : : enable_from_other < T , U , const U & > * = nullptr ,
detail : : enable_if_t < ! std : : is_convertible < const U & , T > : : value > * =
nullptr >
explicit optional ( const optional < U > & rhs ) {
this - > m_has_value = true ;
new ( std : : addressof ( this - > m_value ) ) T ( * rhs ) ;
}
/// Converting move constructor.
/// \synopsis template <class U> optional(optional<U> &&rhs);
template <
class U , detail : : enable_from_other < T , U , U & & > * = nullptr ,
detail : : enable_if_t < std : : is_convertible < U & & , T > : : value > * = nullptr >
optional ( optional < U > & & rhs ) {
this - > m_has_value = true ;
new ( std : : addressof ( this - > m_value ) ) T ( std : : move ( * rhs ) ) ;
}
/// \exclude
template <
class U , detail : : enable_from_other < T , U , U & & > * = nullptr ,
detail : : enable_if_t < ! std : : is_convertible < U & & , T > : : value > * = nullptr >
explicit optional ( optional < U > & & rhs ) {
this - > m_has_value = true ;
new ( std : : addressof ( this - > m_value ) ) T ( std : : move ( * rhs ) ) ;
}
/// Destructor.
~ optional ( ) = default ;
/// Assignment to empty.
///
/// Destroys the current value if there is one.
optional & operator = ( nullopt_t ) noexcept {
if ( has_value ( ) ) {
this - > m_value . ~ T ( ) ;
this - > m_has_value = false ;
}
}
// TODO conditionally delete, check exception guarantee
/// Copy assignment.
///
/// Copies the value from `rhs` if there is one. Otherwise resets the stored value in `*this`.
optional & operator = ( const optional & rhs ) {
if ( has_value ( ) ) {
if ( rhs . has_value ( ) ) {
this - > m_value = rhs . m_value ;
} else {
this - > m_value . ~ T ( ) ;
this - > m_has_value = false ;
}
}
if ( rhs . has_value ( ) ) {
new ( std : : addressof ( this - > m_value ) ) T ( rhs . m_value ) ;
this - > m_has_value = true ;
}
}
// TODO conditionally delete, check exception guarantee
/// Move assignment.
///
/// Moves the value from `rhs` if there is one. Otherwise resets the stored value in `*this`.
optional & operator = ( optional & & rhs ) noexcept (
std : : is_nothrow_move_assignable < T > : : value
& & std : : is_nothrow_move_constructible < T > : : value ) {
if ( has_value ( ) ) {
if ( rhs . has_value ( ) ) {
this - > m_value = std : : move ( rhs . m_value ) ;
} else {
this - > m_value . ~ T ( ) ;
this - > m_has_value = false ;
}
}
if ( rhs . has_value ( ) ) {
new ( std : : addressof ( this - > m_value ) ) T ( std : : move ( rhs . m_value ) ) ;
this - > m_has_value = true ;
}
}
// TODO conditionally delete, check exception guarantee
/// Assigns the stored value from `u`, destroying the old value if there was one.
/// \synopsis optional &operator=(U &&u);
template < class U = T , detail : : enable_assign_forward < T , U > * = nullptr >
optional & operator = ( U & & u ) {
if ( has_value ( ) ) {
this - > m_value = std : : forward < U > ( u ) ;
} else {
new ( std : : addressof ( this - > m_value ) ) T ( std : : forward < U > ( u ) ) ;
this - > m_has_value = true ;
}
}
// TODO check exception guarantee
/// Converting copy assignment operator.
///
/// Copies the value from `rhs` if there is one. Otherwise resets the stored value in `*this`.
/// \synopsis optional &operator=(const optional<U> & rhs);
template < class U ,
detail : : enable_assign_from_other < T , U , const U & > * = nullptr >
optional & operator = ( const optional < U > & rhs ) {
if ( has_value ( ) ) {
if ( rhs . has_value ( ) ) {
this - > m_value = rhs . m_value ;
} else {
this - > m_value . ~ T ( ) ;
this - > m_has_value = false ;
}
}
if ( rhs . has_value ( ) ) {
new ( std : : addressof ( this - > m_value ) ) T ( rhs . m_value ) ;
this - > m_has_value = true ;
}
}
// TODO check exception guarantee
/// Converting move assignment operator.
///
/// Moves the value from `rhs` if there is one. Otherwise resets the stored value in `*this`.
/// \synopsis optional &operator=(optional<U> && rhs);
template < class U , detail : : enable_assign_from_other < T , U , U > * = nullptr >
optional & operator = ( optional < U > & & rhs ) {
if ( has_value ( ) ) {
if ( rhs . has_value ( ) ) {
this - > m_value = std : : move ( rhs . m_value ) ;
} else {
this - > m_value . ~ T ( ) ;
this - > m_has_value = false ;
}
}
if ( rhs . has_value ( ) ) {
new ( std : : addressof ( this - > m_value ) ) T ( std : : move ( rhs . m_value ) ) ;
this - > m_has_value = true ;
}
}
/// Constructs the value in-place, destroying the current one if there is one.
/// \group emplace
template < class . . . Args > T & emplace ( Args & & . . . args ) {
static_assert ( std : : is_constructible < T , Args & & . . . > : : value ,
" T must be constructible with Args " ) ;
* this = nullopt ;
new ( std : : addressof ( this - > m_value ) ) T ( std : : forward < Args > ( args ) . . . ) ;
}
/// \group emplace
/// \synopsis template <class U, class... Args>\nT& emplace(std::initializer_list<U> il, Args &&... args);
template < class U , class . . . Args >
detail : : enable_if_t <
std : : is_constructible < T , std : : initializer_list < U > & , Args & & . . . > : : value ,
T & >
emplace ( std : : initializer_list < U > il , Args & & . . . args ) {
* this = nullopt ;
new ( std : : addressof ( this - > m_value ) ) T ( il , std : : forward < Args > ( args ) . . . ) ;
}
/// Swaps this optional with the other.
///
/// If neither optionals have a value, nothing happens.
/// If both have a value, the values are swapped.
/// If one has a value, it is moved to the other and the movee is left valueless.
void
swap ( optional & rhs ) noexcept ( std : : is_nothrow_move_constructible < T > : : value
& & detail : : is_nothrow_swappable < T > : : value ) {
if ( has_value ( ) ) {
if ( rhs . has_value ( ) ) {
using std : : swap ;
swap ( * * this , * rhs ) ;
} else {
new ( & rhs . m_value ) T ( std : : move ( this - > m_value ) ) ;
this - > m_value . T : : ~ T ( ) ;
}
} else if ( rhs . has_value ( ) ) {
new ( std : : addressof ( this - > m_value ) ) T ( std : : move ( rhs . m_value ) ) ;
rhs . m_value . T : : ~ T ( ) ;
}
}
/// \returns a pointer to the stored value
/// \requires a value is stored
/// \group pointer
/// \synopsis constexpr const T *operator->() const;
constexpr const T * operator - > ( ) const {
return std : : addressof ( this - > m_value ) ;
}
/// \group pointer
/// \synopsis constexpr T *operator->();
TL_OPTIONAL_11_CONSTEXPR T * operator - > ( ) {
return std : : addressof ( this - > m_value ) ;
}
/// \returns the stored value
/// \requires a value is stored
/// \group deref
/// \synopsis constexpr T &operator*();
TL_OPTIONAL_11_CONSTEXPR T & operator * ( ) & { return this - > m_value ; }
/// \group deref
/// \synopsis constexpr const T &operator*() const;
constexpr const T & operator * ( ) const & { return this - > m_value ; }
/// \exclude
TL_OPTIONAL_11_CONSTEXPR T & & operator * ( ) & & {
return std : : move ( this - > m_value ) ;
}
/// \exclude
constexpr const T & & operator * ( ) const & & { return std : : move ( this - > m_value ) ; }
/// \returns whether or not the optional has a value
/// \group has_value
constexpr bool has_value ( ) const noexcept { return this - > m_has_value ; }
/// \group has_value
constexpr explicit operator bool ( ) const noexcept {
return this - > m_has_value ;
}
/// \returns the contained value if there is one, otherwise throws [bad_optional_access]
/// \group value
/// \synopsis constexpr T &value();
TL_OPTIONAL_11_CONSTEXPR T & value ( ) & {
if ( has_value ( ) )
return this - > m_value ;
throw bad_optional_access ( ) ;
}
/// \group value
/// \synopsis constexpr const T &value() const;
TL_OPTIONAL_11_CONSTEXPR const T & value ( ) const & {
if ( has_value ( ) )
return this - > m_value ;
throw bad_optional_access ( ) ;
}
/// \exclude
TL_OPTIONAL_11_CONSTEXPR T & & value ( ) & & {
if ( has_value ( ) )
return std : : move ( this - > m_value ) ;
throw bad_optional_access ( ) ;
}
/// \exclude
constexpr const T & & value ( ) const & & {
if ( has_value ( ) )
return std : : move ( this - > m_value ) ;
throw bad_optional_access ( ) ;
}
/// \returns the stored value if there is one, otherwise returns `u`
/// \group value_or
template < class U > constexpr T value_or ( U & & u ) const & {
static_assert ( std : : is_copy_constructible < T > : : value & &
std : : is_convertible < U & & , T > : : value ,
" T must be copy constructible and convertible from U " ) ;
return has_value ( ) ? * * this : static_cast < T > ( std : : forward < U > ( u ) ) ;
}
/// \group value_or
template < class U > constexpr T value_or ( U & & u ) & & {
static_assert ( std : : is_move_constructible < T > : : value & &
std : : is_convertible < U & & , T > : : value ,
" T must be move constructible and convertible from U " ) ;
return has_value ( ) ? * * this : static_cast < T > ( std : : forward < U > ( u ) ) ;
}
/// Destroys the stored value if one exists, making the optional empty
void reset ( ) noexcept {
if ( has_value ( ) ) {
this - > m_value . ~ T ( ) ;
this - > m_has_value = false ;
}
}
} ;
2017-10-21 09:33:16 +01:00
/// \group relop
/// \brief Compares two optional objects
/// \details If both optionals contain a value, they are compared with `T`s relational operators.
/// Otherwise `lhs` and `rhs` are equal only if they are both empty, and `lhs` is less than `rhs`
/// only if `rhs` is empty and `lhs` is not.
2017-10-02 08:58:09 +01:00
template < class T , class U >
inline constexpr bool operator = = ( const optional < T > & lhs ,
const optional < U > & rhs ) {
return lhs . has_value ( ) = = rhs . has_value ( ) & &
( ! lhs . has_value ( ) | | * lhs = = * rhs ) ;
}
2017-10-21 09:33:16 +01:00
/// \group relop
2017-10-02 08:58:09 +01:00
template < class T , class U >
inline constexpr bool operator ! = ( const optional < T > & lhs ,
const optional < U > & rhs ) {
return lhs . has_value ( ) ! = rhs . has_value ( ) | |
( lhs . has_value ( ) & & * lhs ! = * rhs ) ;
}
2017-10-21 09:33:16 +01:00
/// \group relop
2017-10-02 08:58:09 +01:00
template < class T , class U >
inline constexpr bool operator < ( const optional < T > & lhs ,
const optional < U > & rhs ) {
return rhs . has_value ( ) & & ( ! lhs . has_value ( ) | | * lhs < * rhs ) ;
}
2017-10-21 09:33:16 +01:00
/// \group relop
2017-10-02 08:58:09 +01:00
template < class T , class U >
inline constexpr bool operator > ( const optional < T > & lhs ,
const optional < U > & rhs ) {
return lhs . has_value ( ) & & ( ! rhs . has_value ( ) | | * lhs > * rhs ) ;
}
2017-10-21 09:33:16 +01:00
/// \group relop
2017-10-02 08:58:09 +01:00
template < class T , class U >
inline constexpr bool operator < = ( const optional < T > & lhs ,
const optional < U > & rhs ) {
return ! lhs . has_value ( ) | | ( rhs . has_value ( ) & & * lhs < = * rhs ) ;
}
2017-10-21 09:33:16 +01:00
/// \group relop
2017-10-02 08:58:09 +01:00
template < class T , class U >
inline constexpr bool operator > = ( const optional < T > & lhs ,
const optional < U > & rhs ) {
return ! rhs . has_value ( ) | | ( lhs . has_value ( ) & & * lhs > = * rhs ) ;
}
2017-09-29 19:45:17 +01:00
2017-10-21 09:33:16 +01:00
/// \group relop_nullopt
/// \brief Compares an optional to a `nullopt`
/// \details Equivalent to comparing the optional to an empty optional
2017-10-02 08:58:09 +01:00
template < class T >
inline constexpr bool operator = = ( const optional < T > & lhs , nullopt_t ) noexcept {
return ! lhs . has_value ( ) ;
}
2017-10-21 09:33:16 +01:00
/// \group relop_nullopt
2017-10-02 08:58:09 +01:00
template < class T >
inline constexpr bool operator = = ( nullopt_t , const optional < T > & rhs ) noexcept {
return ! rhs . has_value ( ) ;
}
2017-10-21 09:33:16 +01:00
/// \group relop_nullopt
2017-10-02 08:58:09 +01:00
template < class T >
inline constexpr bool operator ! = ( const optional < T > & lhs , nullopt_t ) noexcept {
return lhs . has_value ( ) ;
}
2017-10-21 09:33:16 +01:00
/// \group relop_nullopt
2017-10-02 08:58:09 +01:00
template < class T >
inline constexpr bool operator ! = ( nullopt_t , const optional < T > & rhs ) noexcept {
return rhs . has_value ( ) ;
}
2017-10-21 09:33:16 +01:00
/// \group relop_nullopt
2017-10-02 08:58:09 +01:00
template < class T >
inline constexpr bool operator < ( const optional < T > & , nullopt_t ) noexcept {
return false ;
}
2017-10-21 09:33:16 +01:00
/// \group relop_nullopt
2017-10-02 08:58:09 +01:00
template < class T >
inline constexpr bool operator < ( nullopt_t , const optional < T > & rhs ) noexcept {
return rhs . has_value ( ) ;
}
2017-10-21 09:33:16 +01:00
/// \group relop_nullopt
2017-10-02 08:58:09 +01:00
template < class T >
inline constexpr bool operator < = ( const optional < T > & lhs , nullopt_t ) noexcept {
return ! lhs . has_value ( ) ;
}
2017-10-21 09:33:16 +01:00
/// \group relop_nullopt
2017-10-02 08:58:09 +01:00
template < class T >
inline constexpr bool operator < = ( nullopt_t , const optional < T > & ) noexcept {
return true ;
}
2017-10-21 09:33:16 +01:00
/// \group relop_nullopt
2017-10-02 08:58:09 +01:00
template < class T >
inline constexpr bool operator > ( const optional < T > & lhs , nullopt_t ) noexcept {
return lhs . has_value ( ) ;
}
2017-10-21 09:33:16 +01:00
/// \group relop_nullopt
2017-10-02 08:58:09 +01:00
template < class T >
inline constexpr bool operator > ( nullopt_t , const optional < T > & ) noexcept {
return false ;
}
2017-10-21 09:33:16 +01:00
/// \group relop_nullopt
2017-10-02 08:58:09 +01:00
template < class T >
inline constexpr bool operator > = ( const optional < T > & , nullopt_t ) noexcept {
return true ;
}
2017-10-21 09:33:16 +01:00
/// \group relop_nullopt
2017-10-02 08:58:09 +01:00
template < class T >
inline constexpr bool operator > = ( nullopt_t , const optional < T > & rhs ) noexcept {
return ! rhs . has_value ( ) ;
}
2017-09-29 19:45:17 +01:00
2017-10-21 09:33:16 +01:00
/// \group relop_t
/// \brief Compares the optional with a value.
/// \details If the optional has a value, it is compared with the other value using `T`s relational operators.
/// Otherwise, the optional is considered less than the value.
2017-10-02 08:58:09 +01:00
template < class T , class U >
inline constexpr bool operator = = ( const optional < T > & lhs , const U & rhs ) {
return lhs . has_value ( ) ? * lhs = = rhs : false ;
}
2017-10-21 09:33:16 +01:00
/// \group relop_t
2017-10-02 08:58:09 +01:00
template < class T , class U >
inline constexpr bool operator = = ( const U & lhs , const optional < T > & rhs ) {
return rhs . has_value ( ) ? lhs = = * rhs : false ;
}
2017-10-21 09:33:16 +01:00
/// \group relop_t
2017-10-02 08:58:09 +01:00
template < class T , class U >
inline constexpr bool operator ! = ( const optional < T > & lhs , const U & rhs ) {
2017-10-02 10:05:36 +01:00
return lhs . has_value ( ) ? * lhs ! = rhs : true ;
2017-10-02 08:58:09 +01:00
}
2017-10-21 09:33:16 +01:00
/// \group relop_t
2017-10-02 08:58:09 +01:00
template < class T , class U >
inline constexpr bool operator ! = ( const U & lhs , const optional < T > & rhs ) {
return rhs . has_value ( ) ? lhs ! = * rhs : true ;
}
2017-10-21 09:33:16 +01:00
/// \group relop_t
2017-10-02 08:58:09 +01:00
template < class T , class U >
inline constexpr bool operator < ( const optional < T > & lhs , const U & rhs ) {
2017-10-02 10:05:36 +01:00
return lhs . has_value ( ) ? * lhs < rhs : true ;
2017-10-02 08:58:09 +01:00
}
2017-10-21 09:33:16 +01:00
/// \group relop_t
2017-10-02 08:58:09 +01:00
template < class T , class U >
inline constexpr bool operator < ( const U & lhs , const optional < T > & rhs ) {
return rhs . has_value ( ) ? lhs < * rhs : false ;
}
2017-10-21 09:33:16 +01:00
/// \group relop_t
2017-10-02 08:58:09 +01:00
template < class T , class U >
inline constexpr bool operator < = ( const optional < T > & lhs , const U & rhs ) {
2017-10-02 10:05:36 +01:00
return lhs . has_value ( ) ? * lhs < = rhs : true ;
2017-10-02 08:58:09 +01:00
}
2017-10-21 09:33:16 +01:00
/// \group relop_t
2017-10-02 08:58:09 +01:00
template < class T , class U >
inline constexpr bool operator < = ( const U & lhs , const optional < T > & rhs ) {
return rhs . has_value ( ) ? lhs < = * rhs : false ;
}
2017-10-21 09:33:16 +01:00
/// \group relop_t
2017-10-02 08:58:09 +01:00
template < class T , class U >
inline constexpr bool operator > ( const optional < T > & lhs , const U & rhs ) {
2017-10-02 10:05:36 +01:00
return lhs . has_value ( ) ? * lhs > rhs : false ;
2017-10-02 08:58:09 +01:00
}
2017-10-21 09:33:16 +01:00
/// \group relop_t
2017-10-02 08:58:09 +01:00
template < class T , class U >
inline constexpr bool operator > ( const U & lhs , const optional < T > & rhs ) {
return rhs . has_value ( ) ? lhs > * rhs : true ;
}
2017-10-21 09:33:16 +01:00
/// \group relop_t
2017-10-02 08:58:09 +01:00
template < class T , class U >
inline constexpr bool operator > = ( const optional < T > & lhs , const U & rhs ) {
2017-10-02 10:05:36 +01:00
return lhs . has_value ( ) ? * lhs > = rhs : false ;
2017-10-02 08:58:09 +01:00
}
2017-10-21 09:33:16 +01:00
/// \group relop_t
2017-10-02 08:58:09 +01:00
template < class T , class U >
inline constexpr bool operator > = ( const U & lhs , const optional < T > & rhs ) {
return rhs . has_value ( ) ? lhs > = * rhs : true ;
}
2017-09-29 19:45:17 +01:00
2017-10-21 09:33:16 +01:00
/// \synopsis template <class T>\nvoid swap(optional<T> &lhs, optional<T> &rhs);
2017-10-02 08:58:09 +01:00
template < class T ,
detail : : enable_if_t < std : : is_move_constructible < T > : : value > * = nullptr ,
detail : : enable_if_t < detail : : is_swappable < T > : : value > * = nullptr >
void swap ( optional < T > & lhs ,
optional < T > & rhs ) noexcept ( noexcept ( lhs . swap ( rhs ) ) ) {
return lhs . swap ( rhs ) ;
}
2017-09-29 19:45:17 +01:00
2017-10-02 08:58:09 +01:00
template < class T >
inline constexpr optional < detail : : decay_t < T > > make_optional ( T & & v ) {
return optional < detail : : decay_t < T > > ( std : : forward < T > ( v ) ) ;
}
template < class T , class . . . Args >
inline constexpr optional < T > make_optional ( Args & & . . . args ) {
return optional < T > ( in_place , std : : forward < Args > ( args ) . . . ) ;
}
template < class T , class U , class . . . Args >
inline constexpr optional < T > make_optional ( std : : initializer_list < U > il ,
Args & & . . . args ) {
return optional < T > ( in_place , il , std : : forward < Args > ( args ) . . . ) ;
}
2017-10-21 19:04:41 +01:00
// template <class T> optional(T)->optional<T>;
2017-10-17 11:54:57 +01:00
} // namespace tl
2017-09-29 19:45:17 +01:00
namespace std {
2017-10-02 08:58:09 +01:00
// TODO SFINAE
template < class T > struct hash < tl : : optional < T > > {
: : std : : size_t operator ( ) ( const tl : : optional < T > & o ) const {
if ( ! o . has_value ( ) )
return 0 ;
2017-09-29 19:45:17 +01:00
2017-10-21 09:33:16 +01:00
return std : : hash < tl : : detail : : remove_const_t < T > > ( ) ( * o ) ;
2017-10-02 08:58:09 +01:00
}
} ;
2017-10-17 11:54:57 +01:00
} // namespace std