cppbind: Refactor to use C++11+ type_traits
This commit is contained in:
parent
9078a085c3
commit
af5833cbc5
@ -492,13 +492,7 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WARNING_FLAGS_C} ${MSVC_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNING_FLAGS_CXX} ${MSVC_FLAGS} ${BOOST_CXX_FLAGS}")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${MSVC_LD_FLAGS}")
|
||||
|
||||
check_cxx_source_compiles("
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
std::make_index_sequence<0> t;
|
||||
int main() { return 0; }"
|
||||
HAVE_STD_INDEX_SEQUENCE
|
||||
)
|
||||
include(CheckCXXFeatures)
|
||||
|
||||
# use BEFORE to ensure local directories are used first,
|
||||
# ahead of system-installed libs
|
||||
|
30
CMakeModules/CheckCXXFeatures.cmake
Normal file
30
CMakeModules/CheckCXXFeatures.cmake
Normal file
@ -0,0 +1,30 @@
|
||||
check_cxx_source_compiles("
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
std::make_index_sequence<0> t;
|
||||
int main() {}" HAVE_STD_INDEX_SEQUENCE
|
||||
)
|
||||
|
||||
check_cxx_source_compiles("
|
||||
#include <type_traits>
|
||||
std::remove_cv_t<const int> t;
|
||||
int main() {}" HAVE_STD_REMOVE_CV_T
|
||||
)
|
||||
|
||||
check_cxx_source_compiles("
|
||||
#include <type_traits>
|
||||
std::remove_cvref_t<const int&> t;
|
||||
int main() {}" HAVE_STD_REMOVE_CVREF_T
|
||||
)
|
||||
|
||||
check_cxx_source_compiles("
|
||||
#include <type_traits>
|
||||
std::enable_if_t<true, int> t;
|
||||
int main() {}" HAVE_STD_ENABLE_IF_T
|
||||
)
|
||||
|
||||
check_cxx_source_compiles("
|
||||
#include <type_traits>
|
||||
std::bool_constant<true> t;
|
||||
int main() {}" HAVE_STD_BOOL_CONSTANT
|
||||
)
|
@ -15,6 +15,7 @@ foreach( mylibfolder
|
||||
nasal/cppbind
|
||||
props
|
||||
serial
|
||||
std
|
||||
structure
|
||||
threads
|
||||
timing
|
||||
|
@ -9,7 +9,6 @@ set(HEADERS
|
||||
SVGpreserveAspectRatio.hxx
|
||||
argparse.hxx
|
||||
interpolator.hxx
|
||||
integer_sequence.hxx
|
||||
make_new.hxx
|
||||
sg_dir.hxx
|
||||
sg_hash.hxx
|
||||
@ -57,10 +56,6 @@ add_executable(test_CSSBorder CSSBorder_test.cxx)
|
||||
add_test(CSSBorder ${EXECUTABLE_OUTPUT_PATH}/test_CSSBorder)
|
||||
target_link_libraries(test_CSSBorder ${TEST_LIBS})
|
||||
|
||||
add_executable(test_integer_sequence integer_sequence_test.cxx)
|
||||
add_test(integer_sequence ${EXECUTABLE_OUTPUT_PATH}/test_integer_sequence)
|
||||
target_link_libraries(test_integer_sequence ${TEST_LIBS})
|
||||
|
||||
add_executable(test_tabbed_values tabbed_values_test.cxx)
|
||||
add_test(tabbed_values ${EXECUTABLE_OUTPUT_PATH}/test_tabbed_values)
|
||||
target_link_libraries(test_tabbed_values ${TEST_LIBS})
|
||||
|
@ -24,17 +24,16 @@
|
||||
#include "NasalObjectHolder.hxx"
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/misc/integer_sequence.hxx>
|
||||
#include <simgear/std/integer_sequence.hxx>
|
||||
#include <simgear/std/type_traits.hxx>
|
||||
#include <simgear/structure/SGWeakReferenced.hxx>
|
||||
#include <simgear/structure/SGWeakPtr.hxx>
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/call_traits.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/lambda/lambda.hpp>
|
||||
#include <boost/mpl/has_xxx.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
|
||||
#include <map>
|
||||
|
||||
@ -62,10 +61,7 @@ namespace osg
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline typename boost::enable_if<
|
||||
boost::is_pointer<T>,
|
||||
T
|
||||
>::type
|
||||
inline std::enable_if_t<std::is_pointer<T>::value, T>
|
||||
get_pointer(T ptr)
|
||||
{
|
||||
return ptr;
|
||||
@ -101,8 +97,8 @@ namespace nasal
|
||||
class GhostMetadata
|
||||
{
|
||||
public:
|
||||
typedef void(*Deleter)(void*);
|
||||
typedef std::vector<std::pair<Deleter, void*> > DestroyList;
|
||||
using Deleter = void(*)(void*);
|
||||
using DestroyList = std::vector<std::pair<Deleter, void*>>;
|
||||
|
||||
static DestroyList _destroy_list;
|
||||
|
||||
@ -154,19 +150,6 @@ namespace nasal
|
||||
};
|
||||
|
||||
BOOST_MPL_HAS_XXX_TRAIT_DEF(element_type)
|
||||
|
||||
template<class T>
|
||||
struct reduced_type
|
||||
{
|
||||
typedef typename boost::remove_cv<
|
||||
typename boost::remove_reference<T>::type
|
||||
>::type type;
|
||||
};
|
||||
|
||||
template<class T1, class T2>
|
||||
struct reduced_is_same:
|
||||
public boost::is_same<typename reduced_type<T1>::type, T2>
|
||||
{};
|
||||
}
|
||||
|
||||
/** @brief Destroy all ghost queued for deletion.
|
||||
@ -178,8 +161,8 @@ namespace nasal
|
||||
*/
|
||||
void ghostProcessDestroyList();
|
||||
|
||||
typedef SGSharedPtr<internal::MethodHolder> MethodHolderPtr;
|
||||
typedef SGWeakPtr<internal::MethodHolder> MethodHolderWeakPtr;
|
||||
using MethodHolderPtr = SGSharedPtr<internal::MethodHolder>;
|
||||
using MethodHolderWeakPtr = SGWeakPtr<internal::MethodHolder>;
|
||||
|
||||
// Dummy template to create shorter and easy to understand compile errors if
|
||||
// trying to wrap the wrong type as a Ghost.
|
||||
@ -187,9 +170,10 @@ namespace nasal
|
||||
class Ghost
|
||||
{
|
||||
public:
|
||||
BOOST_STATIC_ASSERT(("Ghost can only wrap shared pointer!"
|
||||
&& is_strong_ref<T>::value
|
||||
));
|
||||
static_assert(
|
||||
is_strong_ref<T>::value,
|
||||
"Ghost can only wrap shared pointer!"
|
||||
);
|
||||
|
||||
static Ghost& init(const std::string& name);
|
||||
static bool isInit();
|
||||
@ -209,7 +193,7 @@ namespace nasal
|
||||
* int myMember();
|
||||
* void doSomethingElse(const nasal::CallContext& ctx);
|
||||
* }
|
||||
* typedef boost::shared_ptr<MyClass> MyClassPtr;
|
||||
* using MyClassPtr = boost::shared_ptr<MyClass>;
|
||||
*
|
||||
* std::string myOtherFreeMember(int num);
|
||||
*
|
||||
@ -235,29 +219,22 @@ namespace nasal
|
||||
* @endcode
|
||||
*/
|
||||
template<class T>
|
||||
class Ghost<T, typename boost::enable_if<is_strong_ref<T> >::type>:
|
||||
class Ghost<T, std::enable_if_t<is_strong_ref<T>::value>>:
|
||||
public internal::GhostMetadata
|
||||
{
|
||||
// Shared pointer required for Ghost (no weak pointer!)
|
||||
BOOST_STATIC_ASSERT((is_strong_ref<T>::value));
|
||||
|
||||
public:
|
||||
typedef typename T::element_type raw_type;
|
||||
typedef typename shared_ptr_traits<T>::strong_ref strong_ref;
|
||||
typedef typename shared_ptr_traits<T>::weak_ref weak_ref;
|
||||
typedef naRef (raw_type::*member_func_t)(const CallContext&);
|
||||
typedef naRef (*free_func_t)(raw_type&, const CallContext&);
|
||||
typedef boost::function<naRef(raw_type&, naContext)> getter_t;
|
||||
typedef boost::function<void( raw_type&, naContext, naRef)> setter_t;
|
||||
typedef boost::function<naRef(raw_type&, const CallContext&)> method_t;
|
||||
typedef boost::function<bool( raw_type&,
|
||||
naContext,
|
||||
const std::string&,
|
||||
naRef& )> fallback_getter_t;
|
||||
typedef boost::function<bool( raw_type&,
|
||||
naContext,
|
||||
const std::string&,
|
||||
naRef )> fallback_setter_t;
|
||||
using raw_type = typename T::element_type;
|
||||
using strong_ref = typename shared_ptr_traits<T>::strong_ref;
|
||||
using weak_ref = typename shared_ptr_traits<T>::weak_ref;
|
||||
using member_func_t = naRef (raw_type::*)(const CallContext&);
|
||||
using free_func_t = naRef (*)(raw_type&, const CallContext&);
|
||||
using getter_t = boost::function<naRef(raw_type&, naContext)>;
|
||||
using setter_t = boost::function<void( raw_type&, naContext, naRef)>;
|
||||
using method_t = boost::function<naRef(raw_type&, const CallContext&)>;
|
||||
using fallback_getter_t =
|
||||
boost::function<bool(raw_type&, naContext, const std::string&, naRef&)>;
|
||||
using fallback_setter_t =
|
||||
boost::function<bool(raw_type&, naContext, const std::string&, naRef)>;
|
||||
|
||||
template<class Ret, class... Args>
|
||||
using method_variadic_t = boost::function<Ret (raw_type&, Args...)>;
|
||||
@ -272,8 +249,8 @@ namespace nasal
|
||||
|
||||
protected:
|
||||
|
||||
typedef SGSharedPtr<MethodHolder> SharedPtr;
|
||||
typedef SGWeakPtr<MethodHolder> WeakPtr;
|
||||
using SharedPtr = SGSharedPtr<MethodHolder>;
|
||||
using WeakPtr = SGWeakPtr<MethodHolder>;
|
||||
|
||||
method_t _method;
|
||||
|
||||
@ -372,7 +349,7 @@ namespace nasal
|
||||
MethodHolderPtr func;
|
||||
};
|
||||
|
||||
typedef std::map<std::string, member_t> MemberMap;
|
||||
using MemberMap = std::map<std::string, member_t>;
|
||||
|
||||
/**
|
||||
* Register a new ghost type.
|
||||
@ -409,19 +386,18 @@ namespace nasal
|
||||
* @endcode
|
||||
*/
|
||||
template<class BaseGhost>
|
||||
typename boost::enable_if
|
||||
<
|
||||
boost::is_base_of<GhostMetadata, BaseGhost>,
|
||||
Ghost
|
||||
>::type&
|
||||
std::enable_if_t<
|
||||
std::is_base_of<GhostMetadata, BaseGhost>::value,
|
||||
Ghost&
|
||||
>
|
||||
bases()
|
||||
{
|
||||
BOOST_STATIC_ASSERT
|
||||
((
|
||||
boost::is_base_of<typename BaseGhost::raw_type, raw_type>::value
|
||||
));
|
||||
static_assert(
|
||||
std::is_base_of<typename BaseGhost::raw_type, raw_type>::value,
|
||||
"Not a base class!"
|
||||
);
|
||||
|
||||
typedef typename BaseGhost::strong_ref base_ref;
|
||||
using base_ref = typename BaseGhost::strong_ref;
|
||||
|
||||
BaseGhost* base = BaseGhost::getSingletonPtr();
|
||||
base->addDerived(
|
||||
@ -467,17 +443,16 @@ namespace nasal
|
||||
* @endcode
|
||||
*/
|
||||
template<class Base>
|
||||
typename boost::disable_if
|
||||
<
|
||||
boost::is_base_of<GhostMetadata, Base>,
|
||||
Ghost
|
||||
>::type&
|
||||
std::enable_if_t<
|
||||
!std::is_base_of<GhostMetadata, Base>::value,
|
||||
Ghost&
|
||||
>
|
||||
bases()
|
||||
{
|
||||
BOOST_STATIC_ASSERT
|
||||
((
|
||||
boost::is_base_of<typename Ghost<Base>::raw_type, raw_type>::value
|
||||
));
|
||||
static_assert(
|
||||
std::is_base_of<typename Ghost<Base>::raw_type, raw_type>::value,
|
||||
"Not a base class!"
|
||||
);
|
||||
|
||||
return bases< Ghost<Base> >();
|
||||
}
|
||||
@ -853,10 +828,10 @@ namespace nasal
|
||||
)
|
||||
{
|
||||
static_assert(
|
||||
boost::is_convertible<raw_type&, Type>::value,
|
||||
//|| boost::is_convertible<raw_type*, Type>::value
|
||||
std::is_convertible<raw_type&, Type>::value,
|
||||
//|| std::is_convertible<raw_type*, Type>::value
|
||||
// TODO check how to do it with pointer...
|
||||
"First parameter can not be converted from the Ghost raw_type"
|
||||
"First parameter can not be converted from the Ghost raw_type!"
|
||||
);
|
||||
|
||||
return method(name, method_variadic_t<Ret, Args...>(fn));
|
||||
@ -868,11 +843,11 @@ namespace nasal
|
||||
*/
|
||||
template<class RefType>
|
||||
static
|
||||
typename boost::enable_if_c<
|
||||
boost::is_same<RefType, strong_ref>::value
|
||||
|| boost::is_same<RefType, weak_ref>::value,
|
||||
std::enable_if_t<
|
||||
std::is_same<RefType, strong_ref>::value
|
||||
|| std::is_same<RefType, weak_ref>::value,
|
||||
naRef
|
||||
>::type
|
||||
>
|
||||
makeGhost(naContext c, RefType const& ref_ptr)
|
||||
{
|
||||
strong_ref ref(ref_ptr);
|
||||
@ -927,13 +902,10 @@ namespace nasal
|
||||
if( !naIsVector(na_parents) )
|
||||
return strong_ref();
|
||||
|
||||
typedef std::vector<naRef> naRefs;
|
||||
naRefs parents = from_nasal<naRefs>(c, na_parents);
|
||||
for( naRefs::const_iterator parent = parents.begin();
|
||||
parent != parents.end();
|
||||
++parent )
|
||||
auto parents = from_nasal<std::vector<naRef>>(c, na_parents);
|
||||
for(auto parent: parents)
|
||||
{
|
||||
strong_ref ref = fromNasal(c, *parent);
|
||||
strong_ref ref = fromNasal(c, parent);
|
||||
if( get_pointer(ref) )
|
||||
return ref;
|
||||
}
|
||||
@ -985,8 +957,9 @@ namespace nasal
|
||||
static naGhostType _ghost_type_strong, //!< Stored as shared pointer
|
||||
_ghost_type_weak; //!< Stored as weak shared pointer
|
||||
|
||||
typedef naRef (*to_nasal_t)(naContext, const strong_ref&, bool);
|
||||
typedef strong_ref (*from_nasal_t)(naContext, naRef);
|
||||
using to_nasal_t = naRef (*)(naContext, const strong_ref&, bool);
|
||||
using from_nasal_t = strong_ref (*)(naContext, naRef);
|
||||
|
||||
struct DerivedInfo
|
||||
{
|
||||
to_nasal_t to_nasal;
|
||||
@ -999,7 +972,7 @@ namespace nasal
|
||||
{}
|
||||
};
|
||||
|
||||
typedef std::vector<DerivedInfo> DerivedList;
|
||||
using DerivedList = std::vector<DerivedInfo>;
|
||||
DerivedList _derived_types;
|
||||
|
||||
static bool isInstance(naGhostType* ghost_type, bool& is_weak)
|
||||
@ -1013,13 +986,10 @@ namespace nasal
|
||||
|
||||
template<class RefPtr, bool is_weak>
|
||||
static
|
||||
typename boost::enable_if_c<
|
||||
!is_weak,
|
||||
RefPtr
|
||||
>::type
|
||||
std::enable_if_t<!is_weak, RefPtr>
|
||||
getPtr(void* ptr)
|
||||
{
|
||||
typedef shared_ptr_storage<strong_ref> storage_type;
|
||||
using storage_type = shared_ptr_storage<strong_ref>;
|
||||
if( ptr )
|
||||
return storage_type::template get<RefPtr>(
|
||||
static_cast<typename storage_type::storage_type*>(ptr)
|
||||
@ -1030,13 +1000,13 @@ namespace nasal
|
||||
|
||||
template<class RefPtr, bool is_weak>
|
||||
static
|
||||
typename boost::enable_if_c<
|
||||
std::enable_if_t<
|
||||
is_weak && supports_weak_ref<T>::value,
|
||||
RefPtr
|
||||
>::type
|
||||
>
|
||||
getPtr(void* ptr)
|
||||
{
|
||||
typedef shared_ptr_storage<weak_ref> storage_type;
|
||||
using storage_type = shared_ptr_storage<weak_ref>;
|
||||
if( ptr )
|
||||
return storage_type::template get<RefPtr>(
|
||||
static_cast<typename storage_type::storage_type*>(ptr)
|
||||
@ -1047,10 +1017,10 @@ namespace nasal
|
||||
|
||||
template<class RefPtr, bool is_weak>
|
||||
static
|
||||
typename boost::enable_if_c<
|
||||
std::enable_if_t<
|
||||
is_weak && !supports_weak_ref<T>::value,
|
||||
RefPtr
|
||||
>::type
|
||||
>
|
||||
getPtr(void* ptr)
|
||||
{
|
||||
return RefPtr();
|
||||
@ -1066,10 +1036,10 @@ namespace nasal
|
||||
|
||||
template<class BaseGhost>
|
||||
static
|
||||
typename boost::enable_if
|
||||
< boost::is_polymorphic<typename BaseGhost::raw_type>,
|
||||
std::enable_if_t<
|
||||
std::is_polymorphic<typename BaseGhost::raw_type>::value,
|
||||
naRef
|
||||
>::type
|
||||
>
|
||||
toNasal( naContext c,
|
||||
const typename BaseGhost::strong_ref& base_ref,
|
||||
bool strong )
|
||||
@ -1078,8 +1048,8 @@ namespace nasal
|
||||
|
||||
// Check first if passed pointer can by converted to instance of class
|
||||
// this ghost wraps.
|
||||
if( !boost::is_same
|
||||
< typename BaseGhost::raw_type,
|
||||
if( !std::is_same<
|
||||
typename BaseGhost::raw_type,
|
||||
typename Ghost::raw_type
|
||||
>::value
|
||||
&& dynamic_cast<const typename Ghost::raw_type*>(ptr) != ptr )
|
||||
@ -1120,10 +1090,10 @@ namespace nasal
|
||||
|
||||
template<class BaseGhost>
|
||||
static
|
||||
typename boost::disable_if
|
||||
< boost::is_polymorphic<typename BaseGhost::raw_type>,
|
||||
std::enable_if_t<
|
||||
!std::is_polymorphic<typename BaseGhost::raw_type>::value,
|
||||
naRef
|
||||
>::type
|
||||
>
|
||||
toNasal( naContext c,
|
||||
const typename BaseGhost::strong_ref& ref,
|
||||
bool strong )
|
||||
@ -1149,7 +1119,7 @@ namespace nasal
|
||||
template<class Ret>
|
||||
getter_t to_getter(Ret (raw_type::*getter)() const)
|
||||
{
|
||||
typedef typename boost::call_traits<Ret>::param_type param_type;
|
||||
using param_type = typename boost::call_traits<Ret>::param_type;
|
||||
naRef(*to_nasal_)(naContext, param_type) = &to_nasal;
|
||||
|
||||
// Getter signature: naRef(raw_type&, naContext)
|
||||
@ -1202,7 +1172,7 @@ namespace nasal
|
||||
*/
|
||||
template<class Ret>
|
||||
static
|
||||
typename boost::disable_if<boost::is_void<Ret>, naRef>::type
|
||||
std::enable_if_t<!std::is_void<Ret>::value, naRef>
|
||||
method_invoker
|
||||
(
|
||||
const boost::function<Ret (raw_type&, const CallContext&)>& func,
|
||||
@ -1218,7 +1188,7 @@ namespace nasal
|
||||
*/
|
||||
template<class Ret>
|
||||
static
|
||||
typename boost::enable_if<boost::is_void<Ret>, naRef>::type
|
||||
std::enable_if_t<std::is_void<Ret>::value, naRef>
|
||||
method_invoker
|
||||
(
|
||||
const boost::function<Ret (raw_type&, const CallContext&)>& func,
|
||||
@ -1236,10 +1206,10 @@ namespace nasal
|
||||
*/
|
||||
template<class Arg>
|
||||
static
|
||||
typename boost::disable_if<
|
||||
internal::reduced_is_same<Arg, CallContext>,
|
||||
std::enable_if_t<
|
||||
!std::is_same<std::remove_cvref_t<Arg>, CallContext>::value,
|
||||
typename from_nasal_ptr<Arg>::return_type
|
||||
>::type
|
||||
>
|
||||
arg_from_nasal(const CallContext& ctx, size_t index)
|
||||
{
|
||||
return ctx.requireArg<Arg>(index);
|
||||
@ -1250,19 +1220,21 @@ namespace nasal
|
||||
*/
|
||||
template<class Arg>
|
||||
static
|
||||
typename boost::enable_if<
|
||||
internal::reduced_is_same<Arg, CallContext>,
|
||||
std::enable_if_t<
|
||||
std::is_same<std::remove_cvref_t<Arg>, CallContext>::value,
|
||||
typename from_nasal_ptr<Arg>::return_type
|
||||
>::type
|
||||
>
|
||||
arg_from_nasal(const CallContext& ctx, size_t)
|
||||
{
|
||||
// Either const CallContext& or CallContext, non-const reference
|
||||
// does not make sense.
|
||||
BOOST_STATIC_ASSERT( (!boost::is_same<Arg, CallContext&>::value) );
|
||||
static_assert(
|
||||
!boost::is_same<Arg, CallContext&>::value,
|
||||
"Only const reference and value make sense!");
|
||||
return ctx;
|
||||
};
|
||||
|
||||
typedef std::unique_ptr<Ghost> GhostPtr;
|
||||
using GhostPtr = std::unique_ptr<Ghost>;
|
||||
MemberMap _members;
|
||||
fallback_getter_t _fallback_getter;
|
||||
fallback_setter_t _fallback_setter;
|
||||
@ -1302,13 +1274,10 @@ namespace nasal
|
||||
|
||||
template<bool is_weak>
|
||||
static
|
||||
typename boost::enable_if_c<
|
||||
!is_weak,
|
||||
naRef
|
||||
>::type
|
||||
std::enable_if_t<!is_weak, naRef>
|
||||
create(naContext c, const strong_ref& ref_ptr)
|
||||
{
|
||||
typedef shared_ptr_storage<strong_ref> storage_type;
|
||||
using storage_type = shared_ptr_storage<strong_ref>;
|
||||
return naNewGhost2( c,
|
||||
&Ghost::_ghost_type_strong,
|
||||
storage_type::ref(ref_ptr) );
|
||||
@ -1316,13 +1285,13 @@ namespace nasal
|
||||
|
||||
template<bool is_weak>
|
||||
static
|
||||
typename boost::enable_if_c<
|
||||
std::enable_if_t<
|
||||
is_weak && supports_weak_ref<T>::value,
|
||||
naRef
|
||||
>::type
|
||||
>
|
||||
create(naContext c, const strong_ref& ref_ptr)
|
||||
{
|
||||
typedef shared_ptr_storage<weak_ref> storage_type;
|
||||
using storage_type = shared_ptr_storage<weak_ref>;
|
||||
return naNewGhost2( c,
|
||||
&Ghost::_ghost_type_weak,
|
||||
storage_type::ref(ref_ptr) );
|
||||
@ -1330,10 +1299,10 @@ namespace nasal
|
||||
|
||||
template<bool is_weak>
|
||||
static
|
||||
typename boost::enable_if_c<
|
||||
std::enable_if_t<
|
||||
is_weak && !supports_weak_ref<T>::value,
|
||||
naRef
|
||||
>::type
|
||||
>
|
||||
create(naContext, const strong_ref&)
|
||||
{
|
||||
return naNil();
|
||||
@ -1342,7 +1311,7 @@ namespace nasal
|
||||
template<class Type>
|
||||
static void destroy(void *ptr)
|
||||
{
|
||||
typedef shared_ptr_storage<Type> storage_type;
|
||||
using storage_type = shared_ptr_storage<Type>;
|
||||
storage_type::unref(
|
||||
static_cast<typename storage_type::storage_type*>(ptr)
|
||||
);
|
||||
@ -1477,13 +1446,11 @@ namespace nasal
|
||||
|
||||
template<class T>
|
||||
naGhostType
|
||||
Ghost<T, typename boost::enable_if<is_strong_ref<T> >::type>
|
||||
::_ghost_type_strong;
|
||||
Ghost<T, std::enable_if_t<is_strong_ref<T>::value>>::_ghost_type_strong;
|
||||
|
||||
template<class T>
|
||||
naGhostType
|
||||
Ghost<T, typename boost::enable_if<is_strong_ref<T> >::type>
|
||||
::_ghost_type_weak;
|
||||
Ghost<T, std::enable_if_t<is_strong_ref<T>::value>>::_ghost_type_weak;
|
||||
|
||||
} // namespace nasal
|
||||
|
||||
@ -1492,15 +1459,13 @@ namespace nasal
|
||||
* Convert every shared pointer to a ghost.
|
||||
*/
|
||||
template<class T>
|
||||
typename boost::enable_if<
|
||||
nasal::internal::has_element_type<
|
||||
typename nasal::internal::reduced_type<T>::type
|
||||
>,
|
||||
std::enable_if_t<
|
||||
nasal::internal::has_element_type<std::remove_cvref_t<T>>::value,
|
||||
naRef
|
||||
>::type
|
||||
>
|
||||
to_nasal_helper(naContext c, T ptr)
|
||||
{
|
||||
typedef typename nasal::shared_ptr_traits<T>::strong_ref strong_ref;
|
||||
using strong_ref = typename nasal::shared_ptr_traits<T>::strong_ref;
|
||||
return nasal::Ghost<strong_ref>::makeGhost(c, ptr);
|
||||
}
|
||||
|
||||
@ -1508,15 +1473,13 @@ to_nasal_helper(naContext c, T ptr)
|
||||
* Convert nasal ghosts/hashes to shared pointer (of a ghost).
|
||||
*/
|
||||
template<class T>
|
||||
typename boost::enable_if<
|
||||
nasal::internal::has_element_type<
|
||||
typename nasal::internal::reduced_type<T>::type
|
||||
>,
|
||||
std::enable_if_t<
|
||||
nasal::internal::has_element_type<std::remove_cvref_t<T>>::value,
|
||||
T
|
||||
>::type
|
||||
>
|
||||
from_nasal_helper(naContext c, naRef ref, const T*)
|
||||
{
|
||||
typedef typename nasal::shared_ptr_traits<T>::strong_ref strong_ref;
|
||||
using strong_ref = typename nasal::shared_ptr_traits<T>::strong_ref;
|
||||
return T(nasal::Ghost<strong_ref>::fromNasalChecked(c, ref));
|
||||
}
|
||||
|
||||
@ -1524,11 +1487,11 @@ from_nasal_helper(naContext c, naRef ref, const T*)
|
||||
* Convert any pointer to a SGReferenced based object to a ghost.
|
||||
*/
|
||||
template<class T>
|
||||
typename boost::enable_if_c<
|
||||
boost::is_base_of<SGReferenced, T>::value
|
||||
|| boost::is_base_of<SGWeakReferenced, T>::value,
|
||||
std::enable_if_t<
|
||||
std::is_base_of<SGReferenced, T>::value
|
||||
|| std::is_base_of<SGWeakReferenced, T>::value,
|
||||
naRef
|
||||
>::type
|
||||
>
|
||||
to_nasal_helper(naContext c, T* ptr)
|
||||
{
|
||||
return nasal::Ghost<SGSharedPtr<T> >::makeGhost(c, SGSharedPtr<T>(ptr));
|
||||
@ -1538,20 +1501,14 @@ to_nasal_helper(naContext c, T* ptr)
|
||||
* Convert nasal ghosts/hashes to pointer (of a SGReferenced based ghost).
|
||||
*/
|
||||
template<class T>
|
||||
typename boost::enable_if_c<
|
||||
boost::is_base_of<
|
||||
SGReferenced,
|
||||
typename boost::remove_pointer<T>::type
|
||||
>::value
|
||||
|| boost::is_base_of<
|
||||
SGWeakReferenced,
|
||||
typename boost::remove_pointer<T>::type
|
||||
>::value,
|
||||
std::enable_if_t<
|
||||
std::is_base_of<SGReferenced, std::remove_pointer_t<T>>::value
|
||||
|| std::is_base_of<SGWeakReferenced, std::remove_pointer_t<T>>::value,
|
||||
T
|
||||
>::type
|
||||
>
|
||||
from_nasal_helper(naContext c, naRef ref, const T*)
|
||||
{
|
||||
typedef SGSharedPtr<typename boost::remove_pointer<T>::type> TypeRef;
|
||||
using TypeRef = SGSharedPtr<std::remove_pointer_t<T>>;
|
||||
return T(nasal::Ghost<TypeRef>::fromNasalChecked(c, ref));
|
||||
}
|
||||
|
||||
@ -1559,10 +1516,10 @@ from_nasal_helper(naContext c, naRef ref, const T*)
|
||||
* Convert any pointer to a osg::Referenced based object to a ghost.
|
||||
*/
|
||||
template<class T>
|
||||
typename boost::enable_if<
|
||||
boost::is_base_of<osg::Referenced, T>,
|
||||
std::enable_if_t<
|
||||
std::is_base_of<osg::Referenced, T>::value,
|
||||
naRef
|
||||
>::type
|
||||
>
|
||||
to_nasal_helper(naContext c, T* ptr)
|
||||
{
|
||||
return nasal::Ghost<osg::ref_ptr<T> >::makeGhost(c, osg::ref_ptr<T>(ptr));
|
||||
@ -1572,13 +1529,13 @@ to_nasal_helper(naContext c, T* ptr)
|
||||
* Convert nasal ghosts/hashes to pointer (of a osg::Referenced based ghost).
|
||||
*/
|
||||
template<class T>
|
||||
typename boost::enable_if<
|
||||
boost::is_base_of<osg::Referenced, typename boost::remove_pointer<T>::type>,
|
||||
std::enable_if_t<
|
||||
std::is_base_of<osg::Referenced, std::remove_pointer_t<T>>::value,
|
||||
T
|
||||
>::type
|
||||
>
|
||||
from_nasal_helper(naContext c, naRef ref, const T*)
|
||||
{
|
||||
typedef osg::ref_ptr<typename boost::remove_pointer<T>::type> TypeRef;
|
||||
using TypeRef = osg::ref_ptr<std::remove_pointer_t<T>>;
|
||||
return T(nasal::Ghost<TypeRef>::fromNasalChecked(c, ref));
|
||||
}
|
||||
|
||||
|
@ -20,10 +20,7 @@
|
||||
#ifndef SG_NASAL_TRAITS_HXX_
|
||||
#define SG_NASAL_TRAITS_HXX_
|
||||
|
||||
#include <boost/mpl/logical.hpp>
|
||||
#include <boost/type_traits/integral_constant.hpp>
|
||||
#include <boost/type_traits/is_base_of.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <simgear/std/type_traits.hxx>
|
||||
|
||||
// Forward declarations
|
||||
class SGReferenced;
|
||||
@ -56,12 +53,11 @@ namespace osg
|
||||
namespace nasal
|
||||
{
|
||||
template<class T>
|
||||
struct is_vec2: public boost::integral_constant<bool, false> {};
|
||||
struct is_vec2: public std::false_type {};
|
||||
|
||||
#define SG_MAKE_TRAIT(templ,type,attr)\
|
||||
template templ\
|
||||
struct attr< type >:\
|
||||
public boost::integral_constant<bool, true> {};
|
||||
struct attr< type >: public std::true_type {};
|
||||
|
||||
SG_MAKE_TRAIT(<class T>, SGVec2<T>, is_vec2)
|
||||
SG_MAKE_TRAIT(<>, osg::Vec2b, is_vec2)
|
||||
@ -75,42 +71,34 @@ SG_MAKE_TRAIT(<>, osg::Vec2s, is_vec2)
|
||||
struct shared_ptr_traits;
|
||||
|
||||
template<class T>
|
||||
struct is_strong_ref:
|
||||
public boost::integral_constant<bool, false>
|
||||
{};
|
||||
struct is_strong_ref: public std::false_type {};
|
||||
|
||||
template<class T>
|
||||
struct is_weak_ref:
|
||||
public boost::integral_constant<bool, false>
|
||||
{};
|
||||
struct is_weak_ref: public std::false_type {};
|
||||
|
||||
#define SG_MAKE_SHARED_PTR_TRAIT(strong, weak, intrusive)\
|
||||
template<class T>\
|
||||
struct shared_ptr_traits<strong<T> >\
|
||||
{\
|
||||
typedef strong<T> strong_ref;\
|
||||
typedef weak<T> weak_ref;\
|
||||
typedef T element_type;\
|
||||
typedef boost::integral_constant<bool, true> is_strong;\
|
||||
typedef boost::integral_constant<bool, intrusive> is_intrusive;\
|
||||
using strong_ref = strong<T>;\
|
||||
using weak_ref = weak<T>;\
|
||||
using element_type = T;\
|
||||
using is_strong = std::true_type;\
|
||||
using is_intrusive = std::bool_constant<intrusive>;\
|
||||
};\
|
||||
template<class T>\
|
||||
struct shared_ptr_traits<weak<T> >\
|
||||
{\
|
||||
typedef strong<T> strong_ref;\
|
||||
typedef weak<T> weak_ref;\
|
||||
typedef T element_type;\
|
||||
typedef boost::integral_constant<bool, false> is_strong;\
|
||||
typedef boost::integral_constant<bool, intrusive> is_intrusive;\
|
||||
using strong_ref = strong<T>;\
|
||||
using weak_ref = weak<T>;\
|
||||
using element_type = T;\
|
||||
using is_strong = std::false_type;\
|
||||
using is_intrusive = std::bool_constant<intrusive>;\
|
||||
};\
|
||||
template<class T>\
|
||||
struct is_strong_ref<strong<T> >:\
|
||||
public boost::integral_constant<bool, true>\
|
||||
{};\
|
||||
struct is_strong_ref<strong<T> >: public std::true_type {};\
|
||||
template<class T>\
|
||||
struct is_weak_ref<weak<T> >:\
|
||||
public boost::integral_constant<bool, true>\
|
||||
{};
|
||||
struct is_weak_ref<weak<T> >: public std::true_type {};
|
||||
|
||||
SG_MAKE_SHARED_PTR_TRAIT(SGSharedPtr, SGWeakPtr, true)
|
||||
SG_MAKE_SHARED_PTR_TRAIT(osg::ref_ptr, osg::observer_ptr, true)
|
||||
@ -119,25 +107,20 @@ SG_MAKE_TRAIT(<>, osg::Vec2s, is_vec2)
|
||||
#undef SG_MAKE_SHARED_PTR_TRAIT
|
||||
|
||||
template<class T>
|
||||
struct supports_weak_ref:
|
||||
public boost::integral_constant<bool, true>
|
||||
{};
|
||||
struct supports_weak_ref: public std::true_type {};
|
||||
|
||||
template<class T>
|
||||
struct supports_weak_ref<SGSharedPtr<T> >:
|
||||
public boost::integral_constant<
|
||||
bool,
|
||||
boost::is_base_of<SGWeakReferenced, T>::value
|
||||
>
|
||||
public std::bool_constant<std::is_base_of<SGWeakReferenced, T>::value>
|
||||
{};
|
||||
|
||||
template<class T>
|
||||
struct shared_ptr_storage
|
||||
{
|
||||
typedef T storage_type;
|
||||
typedef typename T::element_type element_type;
|
||||
typedef typename shared_ptr_traits<T>::strong_ref strong_ref;
|
||||
typedef typename shared_ptr_traits<T>::weak_ref weak_ref;
|
||||
using storage_type = T;
|
||||
using element_type = typename T::element_type;
|
||||
using strong_ref = typename shared_ptr_traits<T>::strong_ref;
|
||||
using weak_ref = typename shared_ptr_traits<T>::weak_ref;
|
||||
|
||||
template<class U>
|
||||
static storage_type* ref(U ptr)
|
||||
@ -151,39 +134,30 @@ SG_MAKE_TRAIT(<>, osg::Vec2s, is_vec2)
|
||||
|
||||
template<class U>
|
||||
static
|
||||
typename boost::enable_if<
|
||||
boost::is_same<U, element_type*>,
|
||||
element_type*
|
||||
>::type
|
||||
std::enable_if_t<std::is_same<U, element_type*>::value, element_type*>
|
||||
get(storage_type* ptr)
|
||||
{
|
||||
return get_pointer(*ptr);
|
||||
}
|
||||
|
||||
template<class U>
|
||||
static
|
||||
typename boost::enable_if<
|
||||
boost::mpl::or_<
|
||||
boost::is_same<U, strong_ref>,
|
||||
boost::mpl::and_<
|
||||
boost::is_same<U, weak_ref>,
|
||||
supports_weak_ref<U>
|
||||
>
|
||||
>,
|
||||
std::enable_if_t<
|
||||
std::is_same<U, strong_ref>::value
|
||||
|| (std::is_same<U, weak_ref>::value && supports_weak_ref<U>::value),
|
||||
U
|
||||
>::type
|
||||
>
|
||||
get(storage_type* ptr)
|
||||
{
|
||||
return U(*ptr);
|
||||
}
|
||||
|
||||
template<class U>
|
||||
static
|
||||
typename boost::enable_if<
|
||||
boost::mpl::and_<
|
||||
boost::is_same<U, weak_ref>,
|
||||
boost::mpl::not_<supports_weak_ref<U> >
|
||||
>,
|
||||
std::enable_if_t<
|
||||
std::is_same<U, weak_ref>::value && !supports_weak_ref<U>::value,
|
||||
U
|
||||
>::type
|
||||
>
|
||||
get(storage_type* ptr)
|
||||
{
|
||||
return U();
|
||||
@ -195,46 +169,37 @@ SG_MAKE_TRAIT(<>, osg::Vec2s, is_vec2)
|
||||
template<class T>
|
||||
struct intrusive_ptr_storage
|
||||
{
|
||||
typedef typename T::element_type storage_type;
|
||||
typedef typename T::element_type element_type;
|
||||
typedef typename shared_ptr_traits<T>::strong_ref strong_ref;
|
||||
typedef typename shared_ptr_traits<T>::weak_ref weak_ref;
|
||||
using storage_type = typename T::element_type;
|
||||
using element_type = typename T::element_type;
|
||||
using strong_ref = typename shared_ptr_traits<T>::strong_ref;
|
||||
using weak_ref = typename shared_ptr_traits<T>::weak_ref;
|
||||
|
||||
template<class U>
|
||||
static
|
||||
typename boost::enable_if<
|
||||
boost::is_same<U, element_type*>,
|
||||
element_type*
|
||||
>::type
|
||||
std::enable_if_t<std::is_same<U, element_type*>::value, element_type*>
|
||||
get(storage_type* ptr)
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
|
||||
template<class U>
|
||||
static
|
||||
typename boost::enable_if<
|
||||
boost::mpl::or_<
|
||||
boost::is_same<U, strong_ref>,
|
||||
boost::mpl::and_<
|
||||
boost::is_same<U, weak_ref>,
|
||||
supports_weak_ref<U>
|
||||
>
|
||||
>,
|
||||
std::enable_if_t<
|
||||
std::is_same<U, strong_ref>::value
|
||||
|| (std::is_same<U, weak_ref>::value && supports_weak_ref<U>::value),
|
||||
U
|
||||
>::type
|
||||
>
|
||||
get(storage_type* ptr)
|
||||
{
|
||||
return U(ptr);
|
||||
}
|
||||
|
||||
template<class U>
|
||||
static
|
||||
typename boost::enable_if<
|
||||
boost::mpl::and_<
|
||||
boost::is_same<U, weak_ref>,
|
||||
boost::mpl::not_<supports_weak_ref<U> >
|
||||
>,
|
||||
std::enable_if_t<
|
||||
std::is_same<U, weak_ref>::value && !supports_weak_ref<U>::value,
|
||||
U
|
||||
>::type
|
||||
>
|
||||
get(storage_type* ptr)
|
||||
{
|
||||
return U();
|
||||
@ -246,8 +211,8 @@ SG_MAKE_TRAIT(<>, osg::Vec2s, is_vec2)
|
||||
struct shared_ptr_storage<SGSharedPtr<T> >:
|
||||
public internal::intrusive_ptr_storage<SGSharedPtr<T> >
|
||||
{
|
||||
typedef T storage_type;
|
||||
typedef T element_type;
|
||||
using storage_type = T;
|
||||
using element_type = T;
|
||||
|
||||
static storage_type* ref(element_type* ptr)
|
||||
{
|
||||
@ -265,8 +230,8 @@ SG_MAKE_TRAIT(<>, osg::Vec2s, is_vec2)
|
||||
struct shared_ptr_storage<osg::ref_ptr<T> >:
|
||||
public internal::intrusive_ptr_storage<osg::ref_ptr<T> >
|
||||
{
|
||||
typedef T storage_type;
|
||||
typedef T element_type;
|
||||
using storage_type = T;
|
||||
using element_type = T;
|
||||
|
||||
|
||||
static storage_type* ref(element_type* ptr)
|
||||
|
@ -16,6 +16,10 @@
|
||||
#cmakedefine HAVE_MKDTEMP
|
||||
#cmakedefine HAVE_AL_EXT_H
|
||||
#cmakedefine HAVE_STD_INDEX_SEQUENCE
|
||||
#cmakedefine HAVE_STD_REMOVE_CV_T
|
||||
#cmakedefine HAVE_STD_REMOVE_CVREF_T
|
||||
#cmakedefine HAVE_STD_ENABLE_IF_T
|
||||
#cmakedefine HAVE_STD_BOOL_CONSTANT
|
||||
|
||||
#cmakedefine GCC_ATOMIC_BUILTINS_FOUND
|
||||
|
||||
|
21
simgear/std/CMakeLists.txt
Normal file
21
simgear/std/CMakeLists.txt
Normal file
@ -0,0 +1,21 @@
|
||||
include (SimGearComponent)
|
||||
|
||||
set(HEADERS
|
||||
integer_sequence.hxx
|
||||
type_traits.hxx
|
||||
)
|
||||
|
||||
set(SOURCES
|
||||
)
|
||||
|
||||
simgear_component(std std "${SOURCES}" "${HEADERS}")
|
||||
|
||||
if(ENABLE_TESTS)
|
||||
add_executable(test_integer_sequence integer_sequence_test.cxx)
|
||||
add_test(integer_sequence ${EXECUTABLE_OUTPUT_PATH}/test_integer_sequence)
|
||||
target_link_libraries(test_integer_sequence ${TEST_LIBS})
|
||||
|
||||
add_executable(test_type_traits type_traits_test.cxx)
|
||||
add_test(type_traits ${EXECUTABLE_OUTPUT_PATH}/test_type_traits)
|
||||
target_link_libraries(test_type_traits ${TEST_LIBS})
|
||||
endif()
|
@ -17,13 +17,13 @@
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#ifndef SIMGEAR_MISC_INTEGER_SEQUENCE_HXX_
|
||||
#define SIMGEAR_MISC_INTEGER_SEQUENCE_HXX_
|
||||
#ifndef SIMGEAR_STD_INTEGER_SEQUENCE_HXX_
|
||||
#define SIMGEAR_STD_INTEGER_SEQUENCE_HXX_
|
||||
|
||||
#include <simgear/simgear_config.h>
|
||||
#include "type_traits.hxx"
|
||||
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
|
||||
#ifndef HAVE_STD_INDEX_SEQUENCE
|
||||
# include <cstddef>
|
||||
@ -85,4 +85,4 @@ namespace std
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SIMGEAR_MISC_INTEGER_SEQUENCE_HXX_ */
|
||||
#endif /* SIMGEAR_STD_INTEGER_SEQUENCE_HXX_ */
|
@ -1,5 +1,4 @@
|
||||
#include "integer_sequence.hxx"
|
||||
|
||||
#include <simgear/std/integer_sequence.hxx>
|
||||
#include <iostream>
|
||||
|
||||
template<class T>
|
67
simgear/std/type_traits.hxx
Normal file
67
simgear/std/type_traits.hxx
Normal file
@ -0,0 +1,67 @@
|
||||
///@file
|
||||
/// Type Traits (Provide features of later C++ standards)
|
||||
//
|
||||
// Copyright (C) 2017 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#ifndef SIMGEAR_STD_TYPE_TRAITS_HXX_
|
||||
#define SIMGEAR_STD_TYPE_TRAITS_HXX_
|
||||
|
||||
#include <simgear/simgear_config.h>
|
||||
#include <type_traits>
|
||||
|
||||
namespace std
|
||||
{
|
||||
#ifndef HAVE_STD_REMOVE_CV_T
|
||||
template<class T>
|
||||
using remove_cv_t = typename remove_cv<T>::type;
|
||||
|
||||
template<class T>
|
||||
using remove_const_t = typename remove_const<T>::type;
|
||||
|
||||
template<class T>
|
||||
using remove_volatile_t = typename remove_volatile<T>::type;
|
||||
|
||||
template<class T>
|
||||
using remove_reference_t = typename remove_reference<T>::type;
|
||||
|
||||
template< class T >
|
||||
using remove_pointer_t = typename remove_pointer<T>::type;
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STD_REMOVE_CVREF_T
|
||||
template<class T>
|
||||
struct remove_cvref
|
||||
{
|
||||
using type = remove_cv_t<remove_reference_t<T>>;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
using remove_cvref_t = typename remove_cvref<T>::type;
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STD_ENABLE_IF_T
|
||||
template<bool B, class T = void>
|
||||
using enable_if_t = typename enable_if<B, T>::type;
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STD_BOOL_CONSTANT
|
||||
template <bool B>
|
||||
using bool_constant = integral_constant<bool, B>;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* SIMGEAR_STD_TYPE_TRAITS_HXX_ */
|
24
simgear/std/type_traits_test.cxx
Normal file
24
simgear/std/type_traits_test.cxx
Normal file
@ -0,0 +1,24 @@
|
||||
#include <simgear/std/type_traits.hxx>
|
||||
|
||||
using namespace std;
|
||||
|
||||
template<class T, class U>
|
||||
void assert_same()
|
||||
{
|
||||
static_assert(is_same<T, U>::value, "");
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
assert_same<remove_cv_t<int const volatile>, int>();
|
||||
assert_same<remove_const_t<int const volatile>, int volatile>();
|
||||
assert_same<remove_volatile_t<int const volatile>, int const>();
|
||||
assert_same<remove_reference_t<int const volatile&>, int const volatile>();
|
||||
assert_same<remove_pointer_t<int const volatile*>, int const volatile>();
|
||||
assert_same<remove_cvref_t<int const volatile&>, int>();
|
||||
|
||||
assert_same<enable_if_t<true, double>, double>();
|
||||
assert_same<bool_constant<true>, integral_constant<bool, true>>();
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user