You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
301 lines
10 KiB
301 lines
10 KiB
#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
|
|
|