| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275 | #ifndef BOOST_SERIALIZATION_SMART_CAST_HPP#define BOOST_SERIALIZATION_SMART_CAST_HPP// MS compatible compilers support #pragma once#if defined(_MSC_VER)# 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>#include <boost/serialization/throw_exception.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(__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 typename mpl::eval_if<                            typename mpl::and_<                                mpl::not_<is_base_and_derived<                                    typename remove_reference< T >::type,                                    U                                > >,                                mpl::not_<is_base_and_derived<                                    U,                                    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){            typedef typename mpl::eval_if<                boost::is_polymorphic<U>,                mpl::identity<polymorphic>,                mpl::identity<non_polymorphic>            >::type typex;            return typex::cast(u);        }    };    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_exception(std::bad_cast());                    #endif                    return tmp;                }            };            template<class U>            static T cast(U * u){                typedef                    typename mpl::eval_if<                        typename mpl::and_<                            mpl::not_<is_base_and_derived<                                typename remove_pointer< T >::type,                                U                            > >,                            mpl::not_<is_base_and_derived<                                U,                                typename remove_pointer< T >::type                            > >                        >,                        // borland chokes w/o full qualification here                        mpl::identity<cross>,                        mpl::identity<linear>                    >::type typex;                return typex::cast(u);            }            #else            template<class U>            static T cast(U * u){                T tmp = dynamic_cast< T >(u);                #ifndef NDEBUG                    if ( tmp == 0 ) throw_exception(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){            typedef typename mpl::eval_if<                boost::is_polymorphic<U>,                mpl::identity<polymorphic>,                mpl::identity<non_polymorphic>            >::type typex;            return typex::cast(u);        }    };    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){            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        typename mpl::eval_if<            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        typename mpl::eval_if<boost::is_pointer<U>,            mpl::identity<smart_cast_impl::pointer< T > >,        // else        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
 |