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