williamr@2: williamr@2: // Copyright 2000 John Maddock (john@johnmaddock.co.uk) williamr@2: // Copyright 2000 Jeremy Siek (jsiek@lsc.nd.edu) williamr@2: // Copyright 1999, 2000 Jaakko J„rvi (jaakko.jarvi@cs.utu.fi) williamr@2: // williamr@2: // Use, modification and distribution are subject to the Boost Software License, williamr@2: // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at williamr@2: // http://www.boost.org/LICENSE_1_0.txt). williamr@2: // williamr@2: // See http://www.boost.org/libs/type_traits for most recent version including documentation. williamr@2: williamr@2: #ifndef BOOST_TT_IS_CONVERTIBLE_HPP_INCLUDED williamr@2: #define BOOST_TT_IS_CONVERTIBLE_HPP_INCLUDED williamr@2: williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #ifndef BOOST_NO_IS_ABSTRACT williamr@2: #include williamr@2: #endif williamr@2: williamr@2: #if defined(__MWERKS__) williamr@2: #include williamr@2: #include williamr@2: #endif williamr@2: williamr@2: // should be always the last #include directive williamr@2: #include williamr@2: williamr@2: namespace boost { williamr@2: williamr@2: // is one type convertable to another? williamr@2: // williamr@2: // there are multiple versions of the is_convertible williamr@2: // template, almost every compiler seems to require its williamr@2: // own version. williamr@2: // williamr@2: // Thanks to Andrei Alexandrescu for the original version of the williamr@2: // conversion detection technique! williamr@2: // williamr@2: williamr@2: namespace detail { williamr@2: williamr@2: // MS specific version: williamr@2: williamr@2: #if defined(BOOST_MSVC) && (BOOST_MSVC <= 1300) williamr@2: williamr@2: // This workaround is necessary to handle when From is void williamr@2: // which is normally taken care of by the partial specialization williamr@2: // of the is_convertible typename. williamr@2: using ::boost::type_traits::yes_type; williamr@2: using ::boost::type_traits::no_type; williamr@2: williamr@2: template< typename From > williamr@2: struct does_conversion_exist williamr@2: { williamr@2: template< typename To > struct result_ williamr@2: { williamr@2: static no_type BOOST_TT_DECL _m_check(...); williamr@2: static yes_type BOOST_TT_DECL _m_check(To); williamr@2: static From _m_from; williamr@2: enum { value = sizeof( _m_check(_m_from) ) == sizeof(yes_type) }; williamr@2: }; williamr@2: }; williamr@2: williamr@2: template<> williamr@2: struct does_conversion_exist williamr@2: { williamr@2: template< typename To > struct result_ williamr@2: { williamr@2: enum { value = ::boost::is_void::value }; williamr@2: }; williamr@2: }; williamr@2: williamr@2: template williamr@2: struct is_convertible_basic_impl williamr@2: : does_conversion_exist::template result_ williamr@2: { williamr@2: }; williamr@2: williamr@2: #elif defined(__BORLANDC__) && (__BORLANDC__ < 0x560) williamr@2: // williamr@2: // special version for Borland compilers williamr@2: // this version breaks when used for some williamr@2: // UDT conversions: williamr@2: // williamr@2: template williamr@2: struct is_convertible_impl williamr@2: { williamr@2: #pragma option push -w-8074 williamr@2: // This workaround for Borland breaks the EDG C++ frontend, williamr@2: // so we only use it for Borland. williamr@2: template struct checker williamr@2: { williamr@2: static ::boost::type_traits::no_type BOOST_TT_DECL _m_check(...); williamr@2: static ::boost::type_traits::yes_type BOOST_TT_DECL _m_check(T); williamr@2: }; williamr@2: williamr@2: static From _m_from; williamr@2: static bool const value = sizeof( checker::_m_check(_m_from) ) williamr@2: == sizeof(::boost::type_traits::yes_type); williamr@2: #pragma option pop williamr@2: }; williamr@2: williamr@2: #elif defined(__GNUC__) || defined(__BORLANDC__) && (__BORLANDC__ < 0x600) williamr@2: // special version for gcc compiler + recent Borland versions williamr@2: // note that this does not pass UDT's through (...) williamr@2: williamr@2: struct any_conversion williamr@2: { williamr@2: template any_conversion(const volatile T&); williamr@2: template any_conversion(T&); williamr@2: }; williamr@2: williamr@2: template struct checker williamr@2: { williamr@2: static boost::type_traits::no_type _m_check(any_conversion ...); williamr@2: static boost::type_traits::yes_type _m_check(T, int); williamr@2: }; williamr@2: williamr@2: template williamr@2: struct is_convertible_basic_impl williamr@2: { williamr@2: static From _m_from; williamr@2: static bool const value = sizeof( detail::checker::_m_check(_m_from, 0) ) williamr@2: == sizeof(::boost::type_traits::yes_type); williamr@2: }; williamr@2: williamr@2: #elif (defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 245) && !defined(__ICL)) \ williamr@2: || defined(__IBMCPP__) || defined(__HP_aCC) williamr@2: // williamr@2: // This is *almost* an ideal world implementation as it doesn't rely williamr@2: // on undefined behaviour by passing UDT's through (...). williamr@2: // Unfortunately it doesn't quite pass all the tests for most compilers (sigh...) williamr@2: // Enable this for your compiler if is_convertible_test.cpp will compile it... williamr@2: // williamr@2: // Note we do not enable this for VC7.1, because even though it passes all the williamr@2: // type_traits tests it is known to cause problems when instantiation occurs williamr@2: // deep within the instantiation tree :-( williamr@2: // williamr@2: struct any_conversion williamr@2: { williamr@2: template any_conversion(const volatile T&); williamr@2: // we need this constructor to catch references to functions williamr@2: // (which can not be cv-qualified): williamr@2: template any_conversion(T&); williamr@2: }; williamr@2: williamr@2: template williamr@2: struct is_convertible_basic_impl williamr@2: { williamr@2: static ::boost::type_traits::no_type BOOST_TT_DECL _m_check(any_conversion ...); williamr@2: static ::boost::type_traits::yes_type BOOST_TT_DECL _m_check(To, int); williamr@2: static From _m_from; williamr@2: williamr@2: BOOST_STATIC_CONSTANT(bool, value = williamr@2: sizeof( _m_check(_m_from, 0) ) == sizeof(::boost::type_traits::yes_type) williamr@2: ); williamr@2: }; williamr@2: williamr@2: #elif defined(__DMC__) williamr@2: williamr@2: struct any_conversion williamr@2: { williamr@2: template any_conversion(const volatile T&); williamr@2: // we need this constructor to catch references to functions williamr@2: // (which can not be cv-qualified): williamr@2: template any_conversion(T&); williamr@2: }; williamr@2: williamr@2: template williamr@2: struct is_convertible_basic_impl williamr@2: { williamr@2: // Using '...' doesn't always work on Digital Mars. This version seems to. williamr@2: template williamr@2: static ::boost::type_traits::no_type BOOST_TT_DECL _m_check(any_conversion, float, T); williamr@2: static ::boost::type_traits::yes_type BOOST_TT_DECL _m_check(To, int, int); williamr@2: static From _m_from; williamr@2: williamr@2: // Static constants sometime cause the conversion of _m_from to To to be williamr@2: // called. This doesn't happen with an enum. williamr@2: enum { value = williamr@2: sizeof( _m_check(_m_from, 0, 0) ) == sizeof(::boost::type_traits::yes_type) williamr@2: }; williamr@2: }; williamr@2: williamr@2: #elif defined(__MWERKS__) williamr@2: // williamr@2: // CW works with the technique implemented above for EDG, except when From williamr@2: // is a function type (or a reference to such a type), in which case williamr@2: // any_conversion won't be accepted as a valid conversion. We detect this williamr@2: // exceptional situation and channel it through an alternative algorithm. williamr@2: // williamr@2: williamr@2: template williamr@2: struct is_convertible_basic_impl_aux; williamr@2: williamr@2: struct any_conversion williamr@2: { williamr@2: template any_conversion(const volatile T&); williamr@2: }; williamr@2: williamr@2: template williamr@2: struct is_convertible_basic_impl_aux williamr@2: { williamr@2: static ::boost::type_traits::no_type BOOST_TT_DECL _m_check(any_conversion ...); williamr@2: static ::boost::type_traits::yes_type BOOST_TT_DECL _m_check(To, int); williamr@2: static From _m_from; williamr@2: williamr@2: BOOST_STATIC_CONSTANT(bool, value = williamr@2: sizeof( _m_check(_m_from, 0) ) == sizeof(::boost::type_traits::yes_type) williamr@2: ); williamr@2: }; williamr@2: williamr@2: template williamr@2: struct is_convertible_basic_impl_aux williamr@2: { williamr@2: static ::boost::type_traits::no_type BOOST_TT_DECL _m_check(...); williamr@2: static ::boost::type_traits::yes_type BOOST_TT_DECL _m_check(To); williamr@2: static From _m_from; williamr@2: BOOST_STATIC_CONSTANT(bool, value = williamr@2: sizeof( _m_check(_m_from) ) == sizeof(::boost::type_traits::yes_type) williamr@2: ); williamr@2: }; williamr@2: williamr@2: template williamr@2: struct is_convertible_basic_impl: williamr@2: is_convertible_basic_impl_aux< williamr@2: From,To, williamr@2: ::boost::is_function::type>::value williamr@2: > williamr@2: {}; williamr@2: williamr@2: #else williamr@2: williamr@2: // williamr@2: // This version seems to work pretty well for a wide spectrum of compilers, williamr@2: // however it does rely on undefined behaviour by passing UDT's through (...). williamr@2: // williamr@2: template williamr@2: struct is_convertible_basic_impl williamr@2: { williamr@2: static ::boost::type_traits::no_type BOOST_TT_DECL _m_check(...); williamr@2: static ::boost::type_traits::yes_type BOOST_TT_DECL _m_check(To); williamr@2: static From _m_from; williamr@2: #ifdef BOOST_MSVC williamr@2: #pragma warning(push) williamr@2: #pragma warning(disable:4244) williamr@2: #endif williamr@2: BOOST_STATIC_CONSTANT(bool, value = williamr@2: sizeof( _m_check(_m_from) ) == sizeof(::boost::type_traits::yes_type) williamr@2: ); williamr@2: #ifdef BOOST_MSVC williamr@2: #pragma warning(pop) williamr@2: #endif williamr@2: }; williamr@2: williamr@2: #endif // is_convertible_impl williamr@2: williamr@2: #if defined(__DMC__) williamr@2: // As before, a static constant sometimes causes errors on Digital Mars. williamr@2: template williamr@2: struct is_convertible_impl williamr@2: { williamr@2: typedef typename add_reference::type ref_type; williamr@2: enum { value = williamr@2: (::boost::type_traits::ice_and< williamr@2: ::boost::type_traits::ice_or< williamr@2: ::boost::detail::is_convertible_basic_impl::value, williamr@2: ::boost::is_void::value williamr@2: >::value, williamr@2: ::boost::type_traits::ice_not< williamr@2: ::boost::is_array::value williamr@2: >::value williamr@2: >::value) }; williamr@2: }; williamr@2: #elif !defined(__BORLANDC__) || __BORLANDC__ > 0x551 williamr@2: template williamr@2: struct is_convertible_impl williamr@2: { williamr@2: typedef typename add_reference::type ref_type; williamr@2: BOOST_STATIC_CONSTANT(bool, value = williamr@2: (::boost::type_traits::ice_and< williamr@2: ::boost::type_traits::ice_or< williamr@2: ::boost::detail::is_convertible_basic_impl::value, williamr@2: ::boost::is_void::value williamr@2: >::value, williamr@2: ::boost::type_traits::ice_not< williamr@2: ::boost::is_array::value williamr@2: >::value williamr@2: >::value) williamr@2: ); williamr@2: }; williamr@2: #endif williamr@2: williamr@2: template williamr@2: struct is_convertible_impl_select williamr@2: { williamr@2: template williamr@2: struct rebind williamr@2: { williamr@2: typedef is_convertible_impl type; williamr@2: }; williamr@2: }; williamr@2: williamr@2: template <> williamr@2: struct is_convertible_impl_select williamr@2: { williamr@2: template williamr@2: struct rebind williamr@2: { williamr@2: typedef true_type type; williamr@2: }; williamr@2: }; williamr@2: williamr@2: template <> williamr@2: struct is_convertible_impl_select williamr@2: { williamr@2: template williamr@2: struct rebind williamr@2: { williamr@2: typedef false_type type; williamr@2: }; williamr@2: }; williamr@2: williamr@2: template <> williamr@2: struct is_convertible_impl_select williamr@2: { williamr@2: template williamr@2: struct rebind williamr@2: { williamr@2: typedef false_type type; williamr@2: }; williamr@2: }; williamr@2: williamr@2: template williamr@2: struct is_convertible_impl_dispatch_base williamr@2: { williamr@2: #if !BOOST_WORKAROUND(__HP_aCC, < 60700) williamr@2: typedef is_convertible_impl_select< williamr@2: ::boost::is_arithmetic::value, williamr@2: ::boost::is_arithmetic::value, williamr@2: #ifndef BOOST_NO_IS_ABSTRACT williamr@2: ::boost::is_abstract::value williamr@2: #else williamr@2: false williamr@2: #endif williamr@2: > selector; williamr@2: #else williamr@2: typedef is_convertible_impl_select selector; williamr@2: #endif williamr@2: typedef typename selector::template rebind isc_binder; williamr@2: typedef typename isc_binder::type type; williamr@2: }; williamr@2: williamr@2: template williamr@2: struct is_convertible_impl_dispatch williamr@2: : public is_convertible_impl_dispatch_base::type williamr@2: {}; williamr@2: williamr@2: // williamr@2: // Now add the full and partial specialisations williamr@2: // for void types, these are common to all the williamr@2: // implementation above: williamr@2: // williamr@2: #ifndef BOOST_NO_CV_VOID_SPECIALIZATIONS williamr@2: # define TT_AUX_BOOL_CV_VOID_TRAIT_SPEC2_PART1(trait,spec1,spec2,value) \ williamr@2: BOOST_TT_AUX_BOOL_TRAIT_IMPL_SPEC2(trait,spec1,spec2,value) \ williamr@2: BOOST_TT_AUX_BOOL_TRAIT_IMPL_SPEC2(trait,spec1,spec2 const,value) \ williamr@2: BOOST_TT_AUX_BOOL_TRAIT_IMPL_SPEC2(trait,spec1,spec2 volatile,value) \ williamr@2: BOOST_TT_AUX_BOOL_TRAIT_IMPL_SPEC2(trait,spec1,spec2 const volatile,value) \ williamr@2: /**/ williamr@2: williamr@2: # define TT_AUX_BOOL_CV_VOID_TRAIT_SPEC2(trait,spec1,spec2,value) \ williamr@2: TT_AUX_BOOL_CV_VOID_TRAIT_SPEC2_PART1(trait,spec1,spec2,value) \ williamr@2: TT_AUX_BOOL_CV_VOID_TRAIT_SPEC2_PART1(trait,spec1 const,spec2,value) \ williamr@2: TT_AUX_BOOL_CV_VOID_TRAIT_SPEC2_PART1(trait,spec1 volatile,spec2,value) \ williamr@2: TT_AUX_BOOL_CV_VOID_TRAIT_SPEC2_PART1(trait,spec1 const volatile,spec2,value) \ williamr@2: /**/ williamr@2: williamr@2: TT_AUX_BOOL_CV_VOID_TRAIT_SPEC2(is_convertible,void,void,true) williamr@2: williamr@2: # undef TT_AUX_BOOL_CV_VOID_TRAIT_SPEC2 williamr@2: # undef TT_AUX_BOOL_CV_VOID_TRAIT_SPEC2_PART1 williamr@2: williamr@2: #else williamr@2: BOOST_TT_AUX_BOOL_TRAIT_IMPL_SPEC2(is_convertible,void,void,true) williamr@2: #endif // BOOST_NO_CV_VOID_SPECIALIZATIONS williamr@2: williamr@2: #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION williamr@2: BOOST_TT_AUX_BOOL_TRAIT_IMPL_PARTIAL_SPEC2_1(typename To,is_convertible,void,To,false) williamr@2: BOOST_TT_AUX_BOOL_TRAIT_IMPL_PARTIAL_SPEC2_1(typename From,is_convertible,From,void,true) williamr@2: #ifndef BOOST_NO_CV_VOID_SPECIALIZATIONS williamr@2: BOOST_TT_AUX_BOOL_TRAIT_IMPL_PARTIAL_SPEC2_1(typename To,is_convertible,void const,To,false) williamr@2: BOOST_TT_AUX_BOOL_TRAIT_IMPL_PARTIAL_SPEC2_1(typename To,is_convertible,void volatile,To,false) williamr@2: BOOST_TT_AUX_BOOL_TRAIT_IMPL_PARTIAL_SPEC2_1(typename To,is_convertible,void const volatile,To,false) williamr@2: BOOST_TT_AUX_BOOL_TRAIT_IMPL_PARTIAL_SPEC2_1(typename From,is_convertible,From,void const,true) williamr@2: BOOST_TT_AUX_BOOL_TRAIT_IMPL_PARTIAL_SPEC2_1(typename From,is_convertible,From,void volatile,true) williamr@2: BOOST_TT_AUX_BOOL_TRAIT_IMPL_PARTIAL_SPEC2_1(typename From,is_convertible,From,void const volatile,true) williamr@2: #endif williamr@2: #endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION williamr@2: williamr@2: } // namespace detail williamr@2: williamr@2: BOOST_TT_AUX_BOOL_TRAIT_DEF2(is_convertible,From,To,(::boost::detail::is_convertible_impl_dispatch::value)) williamr@2: williamr@2: } // namespace boost williamr@2: williamr@2: #include williamr@2: williamr@2: #endif // BOOST_TT_IS_CONVERTIBLE_HPP_INCLUDED williamr@2: