#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 |