williamr@2: #ifndef BOOST_SMART_CAST_HPP williamr@2: #define BOOST_SMART_CAST_HPP williamr@2: williamr@2: // MS compatible compilers support #pragma once williamr@2: #if defined(_MSC_VER) && (_MSC_VER >= 1020) williamr@2: # pragma once williamr@2: #endif williamr@2: williamr@2: /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8 williamr@2: // smart_cast.hpp: williamr@2: williamr@2: // (C) Copyright 2002 Robert Ramey - http://www.rrsd.com . williamr@2: // Use, modification and distribution is subject to the Boost Software williamr@2: // License, 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 for updates, documentation, and revision history. williamr@2: williamr@2: // casting of pointers and references. williamr@2: williamr@2: // In casting between different C++ classes, there are a number of williamr@2: // rules that have to be kept in mind in deciding whether to use williamr@2: // static_cast or dynamic_cast. williamr@2: williamr@2: // a) dynamic casting can only be applied when one of the types is polymorphic williamr@2: // Otherwise static_cast must be used. williamr@2: // b) only dynamic casting can do runtime error checking williamr@2: // use of static_cast is generally un checked even when compiled for debug williamr@2: // c) static_cast would be considered faster than dynamic_cast. williamr@2: williamr@2: // If casting is applied to a template parameter, there is no apriori way williamr@2: // to know which of the two casting methods will be permitted or convenient. williamr@2: williamr@2: // smart_cast uses C++ type_traits, and program debug mode to select the williamr@2: // most convenient cast to use. williamr@2: williamr@2: #include williamr@2: #include williamr@2: williamr@2: #include williamr@2: #include 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: williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: williamr@2: namespace boost { williamr@2: namespace smart_cast_impl { williamr@2: williamr@2: template williamr@2: struct reference { williamr@2: williamr@2: struct polymorphic { williamr@2: williamr@2: struct linear { williamr@2: template williamr@2: static T cast(U & u){ williamr@2: return static_cast(u); williamr@2: } williamr@2: }; williamr@2: williamr@2: struct cross { williamr@2: template williamr@2: static T cast(U & u){ williamr@2: return dynamic_cast(u); williamr@2: } williamr@2: }; williamr@2: williamr@2: template williamr@2: static T cast(U & u){ williamr@2: // if we're in debug mode williamr@2: #if ! defined(NDEBUG) \ williamr@2: || defined(__BORLANDC__) && (__BORLANDC__ <= 0x560) \ williamr@2: || defined(__MWERKS__) williamr@2: // do a checked dynamic cast williamr@2: return cross::cast(u); williamr@2: #else williamr@2: // borland 5.51 chokes here so we can't use it williamr@2: // note: if remove_reference isn't function for these types williamr@2: // cross casting will be selected this will work but will williamr@2: // not be the most efficient method. This will conflict with williamr@2: // the original smart_cast motivation. williamr@2: typedef BOOST_DEDUCED_TYPENAME mpl::eval_if< williamr@2: BOOST_DEDUCED_TYPENAME mpl::and_< williamr@2: mpl::not_::type, williamr@2: U williamr@2: > >, williamr@2: mpl::not_::type williamr@2: > > williamr@2: >, williamr@2: // borland chokes w/o full qualification here williamr@2: mpl::identity, williamr@2: mpl::identity williamr@2: >::type typex; williamr@2: // typex works around gcc 2.95 issue williamr@2: return typex::cast(u); williamr@2: #endif williamr@2: } williamr@2: }; williamr@2: williamr@2: struct non_polymorphic { williamr@2: template williamr@2: static T cast(U & u){ williamr@2: return static_cast(u); williamr@2: } williamr@2: }; williamr@2: template williamr@2: static T cast(U & u){ williamr@2: #if defined(__BORLANDC__) williamr@2: return mpl::eval_if< williamr@2: boost::is_polymorphic, williamr@2: mpl::identity, williamr@2: mpl::identity williamr@2: >::type::cast(u); williamr@2: #else williamr@2: typedef BOOST_DEDUCED_TYPENAME mpl::eval_if< williamr@2: boost::is_polymorphic, williamr@2: mpl::identity, williamr@2: mpl::identity williamr@2: >::type typex; williamr@2: return typex::cast(u); williamr@2: #endif williamr@2: } williamr@2: }; williamr@2: williamr@2: template williamr@2: struct pointer { williamr@2: williamr@2: struct polymorphic { williamr@2: // unfortunately, this below fails to work for virtual base williamr@2: // classes. need has_virtual_base to do this. williamr@2: // Subject for further study williamr@2: #if 0 williamr@2: struct linear { williamr@2: template williamr@2: static T cast(U * u){ williamr@2: return static_cast(u); williamr@2: } williamr@2: }; williamr@2: williamr@2: struct cross { williamr@2: template williamr@2: static T cast(U * u){ williamr@2: T tmp = dynamic_cast(u); williamr@2: #ifndef NDEBUG williamr@2: if ( tmp == 0 ) throw std::bad_cast(); williamr@2: #endif williamr@2: return tmp; williamr@2: } williamr@2: }; williamr@2: williamr@2: template williamr@2: static T cast(U * u){ williamr@2: // if we're in debug mode williamr@2: #if ! defined(NDEBUG) || defined(__BORLANDC__) && (__BORLANDC__ <= 0x560) williamr@2: // do a checked dynamic cast williamr@2: return cross::cast(u); williamr@2: #else williamr@2: // borland 5.51 chokes here so we can't use it williamr@2: // note: if remove_pointer isn't function for these types williamr@2: // cross casting will be selected this will work but will williamr@2: // not be the most efficient method. This will conflict with williamr@2: // the original smart_cast motivation. williamr@2: typedef williamr@2: BOOST_DEDUCED_TYPENAME mpl::eval_if< williamr@2: BOOST_DEDUCED_TYPENAME mpl::and_< williamr@2: mpl::not_::type, williamr@2: U williamr@2: > >, williamr@2: mpl::not_::type williamr@2: > > williamr@2: >, williamr@2: // borland chokes w/o full qualification here williamr@2: mpl::identity, williamr@2: mpl::identity williamr@2: >::type typex; williamr@2: return typex::cast(u); williamr@2: #endif williamr@2: } williamr@2: #else williamr@2: template williamr@2: static T cast(U * u){ williamr@2: T tmp = dynamic_cast(u); williamr@2: #ifndef NDEBUG williamr@2: if ( tmp == 0 ) throw std::bad_cast(); williamr@2: #endif williamr@2: return tmp; williamr@2: } williamr@2: #endif williamr@2: }; williamr@2: williamr@2: struct non_polymorphic { williamr@2: template williamr@2: static T cast(U * u){ williamr@2: return static_cast(u); williamr@2: } williamr@2: }; williamr@2: williamr@2: template williamr@2: static T cast(U * u){ williamr@2: #if defined(__BORLANDC__) williamr@2: return mpl::eval_if< williamr@2: boost::is_polymorphic, williamr@2: mpl::identity, williamr@2: mpl::identity williamr@2: >::type::cast(u); williamr@2: #else williamr@2: typedef BOOST_DEDUCED_TYPENAME mpl::eval_if< williamr@2: boost::is_polymorphic, williamr@2: mpl::identity, williamr@2: mpl::identity williamr@2: >::type typex; williamr@2: return typex::cast(u); williamr@2: #endif williamr@2: } williamr@2: williamr@2: }; williamr@2: williamr@2: template williamr@2: struct void_pointer { williamr@2: template williamr@2: static TPtr cast(UPtr uptr){ williamr@2: return static_cast(uptr); williamr@2: } williamr@2: }; williamr@2: williamr@2: template williamr@2: struct error { williamr@2: // if we get here, its because we are using one argument in the williamr@2: // cast on a system which doesn't support partial template williamr@2: // specialization williamr@2: template williamr@2: static T cast(U u){ williamr@2: BOOST_STATIC_ASSERT(sizeof(T)==0); williamr@2: return * static_cast(NULL); williamr@2: } williamr@2: }; williamr@2: williamr@2: } // smart_cast_impl williamr@2: williamr@2: // this implements: williamr@2: // smart_cast(Source * s) williamr@2: // smart_cast(s) williamr@2: // note that it will fail with williamr@2: // smart_cast(s) williamr@2: template williamr@2: T smart_cast(U u) { williamr@2: typedef williamr@2: BOOST_DEDUCED_TYPENAME mpl::eval_if< williamr@2: BOOST_DEDUCED_TYPENAME mpl::or_< williamr@2: boost::is_same, williamr@2: boost::is_same, williamr@2: boost::is_same, williamr@2: boost::is_same williamr@2: >, williamr@2: mpl::identity >, williamr@2: // else williamr@2: BOOST_DEDUCED_TYPENAME mpl::eval_if, williamr@2: mpl::identity >, williamr@2: // else williamr@2: BOOST_DEDUCED_TYPENAME mpl::eval_if, williamr@2: mpl::identity >, williamr@2: // else williamr@2: mpl::identity williamr@2: > williamr@2: > williamr@2: > williamr@2: >::type typex; williamr@2: return typex::cast(u); williamr@2: } williamr@2: williamr@2: // this implements: williamr@2: // smart_cast_reference(Source & s) williamr@2: template williamr@2: T smart_cast_reference(U & u) { williamr@2: return smart_cast_impl::reference::cast(u); williamr@2: } williamr@2: williamr@2: } // namespace boost williamr@2: williamr@2: #endif // BOOST_SMART_CAST_HPP