@ -34,7 +34,9 @@ namespace exopt::types { namespace boxed {
# endif
# endif
return std : : make_unique < T > ( * c ) ; }
return std : : make_unique < T > ( * c ) ; }
template < typename From , typename To >
concept binary_convertible = std : : is_convertible_v < From , To > and std : : is_convertible_v < To , From > ;
template < typename T >
template < typename T >
struct Box {
struct Box {
typedef boxable_value_type < T > : : type type ;
typedef boxable_value_type < T > : : type type ;
@ -102,6 +104,21 @@ namespace exopt::types { namespace boxed {
std : : unique_ptr < T > m_ptr ; // Unique<T> m_ptr;
std : : unique_ptr < T > m_ptr ; // Unique<T> m_ptr;
} ;
} ;
# define _EO_ADD_RV std::add_rvalue_reference_v
template < typename Base , typename T = Base >
constexpr inline bool is_boxable_v = binary_convertible < _EO_ADD_RV < T > , _EO_ADD_RV < Base > > and requires ( T & & value ) {
typename Box < Base > ;
typename Box < Base > : : type ;
{ std : : make_unique < T > ( std : : move ( value ) ) } - > std : : same_as < std : : unique_ptr < T > > ;
} ;
template < typename T > concept is_boxable = is_boxable_v < T > ;
template < typename T >
constexpr inline bool is_nothrow_boxable_v = is_boxable_v < T > & & std : : is_nothrow_constructible_v < Box < T > , T > ;
# undef _EO_ADD_RV
template < typename T , typename U > requires ( requires ( T & & o ) { static_cast < U & & > ( o ) ; } )
template < typename T , typename U > requires ( requires ( T & & o ) { static_cast < U & & > ( o ) ; } )
constexpr Box < U > static_box_cast ( Box < T > & & b ) noexcept { return Box < U > : : from_raw_ptr ( static_cast < U * > ( b . release ( ) ) ) ; }
constexpr Box < U > static_box_cast ( Box < T > & & b ) noexcept { return Box < U > : : from_raw_ptr ( static_cast < U * > ( b . release ( ) ) ) ; }
@ -115,6 +132,21 @@ namespace exopt::types { namespace boxed {
throw ;
throw ;
}
}
} //TODO: Overload for `const&` that does the type check *before* the copy allocation.
} //TODO: Overload for `const&` that does the type check *before* the copy allocation.
template < typename T , typename R /*XXX: Maybe remove this, and put the requires after the definition, using `auto&& value` instead of `R&& value`*/ > requires ( std : : derived_from < R , T > )
constexpr Box < T > box ( R & & value , util : : comptime < bool > auto Check = _EO_CONSTANT_VALUE ( false ) ) noexcept ( std : : is_nothrow_invocable_v < Box < T > : : new_dynamic < R , bool ( Check ) > ) //XXX: This seems illegal...
{ return Box < T > : : template new_dynamic < R , Check > ( std : : move ( value ) ) ; }
template < typename T >
constexpr Box < T > box ( std : : convertible_to < T > auto & & value ) noexcept ( std : : is_nothrow_constructible_v < Box < T > , std : : add_rvalue_reference_v < T > > )
{
/*if constexpr(requires(decltype(value) v) { static_cast<T&&>(std::move(v)); }) {
return Box < T > : : template new_dynamic < T > ( std : : move ( value ) ) ;
} else */ return { static_cast < T > ( std : : move ( value ) ) } ;
}
template < typename T >
constexpr Box < T > box ( T & & value ) noexcept ( std : : is_nothrow_constructible_v < Box < T > , T > )
{ return { std : : move ( value ) } ; }
}
}
using boxed : : Box ;
using boxed : : Box ;
}
}