1 #ifndef BOOST_SERIALIZATION_SMART_CAST_HPP 2 #define BOOST_SERIALIZATION_SMART_CAST_HPP 3 4 // MS compatible compilers support #pragma once 5 #if defined(_MSC_VER) 6 # pragma once 7 #endif 8 9 /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8 10 // smart_cast.hpp: 11 12 // (C) Copyright 2002 Robert Ramey - http://www.rrsd.com . 13 // Use, modification and distribution is subject to the Boost Software 14 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 15 // http://www.boost.org/LICENSE_1_0.txt) 16 17 // See http://www.boost.org/libs/serialization for updates, documentation, and revision history. 18 19 // casting of pointers and references. 20 21 // In casting between different C++ classes, there are a number of 22 // rules that have to be kept in mind in deciding whether to use 23 // static_cast or dynamic_cast. 24 25 // a) dynamic casting can only be applied when one of the types is polymorphic 26 // Otherwise static_cast must be used. 27 // b) only dynamic casting can do runtime error checking 28 // use of static_cast is generally un checked even when compiled for debug 29 // c) static_cast would be considered faster than dynamic_cast. 30 31 // If casting is applied to a template parameter, there is no apriori way 32 // to know which of the two casting methods will be permitted or convenient. 33 34 // smart_cast uses C++ type_traits, and program debug mode to select the 35 // most convenient cast to use. 36 37 #include <exception> 38 #include <typeinfo> 39 #include <cstddef> // NULL 40 41 #include <boost/config.hpp> 42 #include <boost/static_assert.hpp> 43 44 #include <boost/type_traits/is_base_and_derived.hpp> 45 #include <boost/type_traits/is_polymorphic.hpp> 46 #include <boost/type_traits/is_pointer.hpp> 47 #include <boost/type_traits/is_reference.hpp> 48 #include <boost/type_traits/is_same.hpp> 49 #include <boost/type_traits/remove_pointer.hpp> 50 #include <boost/type_traits/remove_reference.hpp> 51 52 #include <boost/mpl/eval_if.hpp> 53 #include <boost/mpl/if.hpp> 54 #include <boost/mpl/or.hpp> 55 #include <boost/mpl/and.hpp> 56 #include <boost/mpl/not.hpp> 57 #include <boost/mpl/identity.hpp> 58 59 #include <boost/serialization/throw_exception.hpp> 60 61 namespace boost { 62 namespace serialization { 63 namespace smart_cast_impl { 64 65 template<class T> 66 struct reference { 67 68 struct polymorphic { 69 70 struct linear { 71 template<class U> castboost::serialization::smart_cast_impl::reference::polymorphic::linear72 static T cast(U & u){ 73 return static_cast< T >(u); 74 } 75 }; 76 77 struct cross { 78 template<class U> castboost::serialization::smart_cast_impl::reference::polymorphic::cross79 static T cast(U & u){ 80 return dynamic_cast< T >(u); 81 } 82 }; 83 84 template<class U> castboost::serialization::smart_cast_impl::reference::polymorphic85 static T cast(U & u){ 86 // if we're in debug mode 87 #if ! defined(NDEBUG) \ 88 || defined(__MWERKS__) 89 // do a checked dynamic cast 90 return cross::cast(u); 91 #else 92 // borland 5.51 chokes here so we can't use it 93 // note: if remove_reference isn't function for these types 94 // cross casting will be selected this will work but will 95 // not be the most efficient method. This will conflict with 96 // the original smart_cast motivation. 97 typedef typename mpl::eval_if< 98 typename mpl::and_< 99 mpl::not_<is_base_and_derived< 100 typename remove_reference< T >::type, 101 U 102 > >, 103 mpl::not_<is_base_and_derived< 104 U, 105 typename remove_reference< T >::type 106 > > 107 >, 108 // borland chokes w/o full qualification here 109 mpl::identity<cross>, 110 mpl::identity<linear> 111 >::type typex; 112 // typex works around gcc 2.95 issue 113 return typex::cast(u); 114 #endif 115 } 116 }; 117 118 struct non_polymorphic { 119 template<class U> castboost::serialization::smart_cast_impl::reference::non_polymorphic120 static T cast(U & u){ 121 return static_cast< T >(u); 122 } 123 }; 124 template<class U> castboost::serialization::smart_cast_impl::reference125 static T cast(U & u){ 126 typedef typename mpl::eval_if< 127 boost::is_polymorphic<U>, 128 mpl::identity<polymorphic>, 129 mpl::identity<non_polymorphic> 130 >::type typex; 131 return typex::cast(u); 132 } 133 }; 134 135 template<class T> 136 struct pointer { 137 138 struct polymorphic { 139 // unfortunately, this below fails to work for virtual base 140 // classes. need has_virtual_base to do this. 141 // Subject for further study 142 #if 0 143 struct linear { 144 template<class U> 145 static T cast(U * u){ 146 return static_cast< T >(u); 147 } 148 }; 149 150 struct cross { 151 template<class U> 152 static T cast(U * u){ 153 T tmp = dynamic_cast< T >(u); 154 #ifndef NDEBUG 155 if ( tmp == 0 ) throw_exception(std::bad_cast()); 156 #endif 157 return tmp; 158 } 159 }; 160 161 template<class U> 162 static T cast(U * u){ 163 typedef 164 typename mpl::eval_if< 165 typename mpl::and_< 166 mpl::not_<is_base_and_derived< 167 typename remove_pointer< T >::type, 168 U 169 > >, 170 mpl::not_<is_base_and_derived< 171 U, 172 typename remove_pointer< T >::type 173 > > 174 >, 175 // borland chokes w/o full qualification here 176 mpl::identity<cross>, 177 mpl::identity<linear> 178 >::type typex; 179 return typex::cast(u); 180 } 181 #else 182 template<class U> castboost::serialization::smart_cast_impl::pointer::polymorphic183 static T cast(U * u){ 184 T tmp = dynamic_cast< T >(u); 185 #ifndef NDEBUG 186 if ( tmp == 0 ) throw_exception(std::bad_cast()); 187 #endif 188 return tmp; 189 } 190 #endif 191 }; 192 193 struct non_polymorphic { 194 template<class U> castboost::serialization::smart_cast_impl::pointer::non_polymorphic195 static T cast(U * u){ 196 return static_cast< T >(u); 197 } 198 }; 199 200 template<class U> castboost::serialization::smart_cast_impl::pointer201 static T cast(U * u){ 202 typedef typename mpl::eval_if< 203 boost::is_polymorphic<U>, 204 mpl::identity<polymorphic>, 205 mpl::identity<non_polymorphic> 206 >::type typex; 207 return typex::cast(u); 208 } 209 210 }; 211 212 template<class TPtr> 213 struct void_pointer { 214 template<class UPtr> castboost::serialization::smart_cast_impl::void_pointer215 static TPtr cast(UPtr uptr){ 216 return static_cast<TPtr>(uptr); 217 } 218 }; 219 220 template<class T> 221 struct error { 222 // if we get here, its because we are using one argument in the 223 // cast on a system which doesn't support partial template 224 // specialization 225 template<class U> castboost::serialization::smart_cast_impl::error226 static T cast(U){ 227 BOOST_STATIC_ASSERT(sizeof(T)==0); 228 return * static_cast<T *>(NULL); 229 } 230 }; 231 232 } // smart_cast_impl 233 234 // this implements: 235 // smart_cast<Target *, Source *>(Source * s) 236 // smart_cast<Target &, Source &>(s) 237 // note that it will fail with 238 // smart_cast<Target &>(s) 239 template<class T, class U> 240 T smart_cast(U u) { 241 typedef 242 typename mpl::eval_if< 243 typename mpl::or_< 244 boost::is_same<void *, U>, 245 boost::is_same<void *, T>, 246 boost::is_same<const void *, U>, 247 boost::is_same<const void *, T> 248 >, 249 mpl::identity<smart_cast_impl::void_pointer< T > >, 250 // else 251 typename mpl::eval_if<boost::is_pointer<U>, 252 mpl::identity<smart_cast_impl::pointer< T > >, 253 // else 254 typename mpl::eval_if<boost::is_reference<U>, 255 mpl::identity<smart_cast_impl::reference< T > >, 256 // else 257 mpl::identity<smart_cast_impl::error< T > 258 > 259 > 260 > 261 >::type typex; 262 return typex::cast(u); 263 } 264 265 // this implements: 266 // smart_cast_reference<Target &>(Source & s) 267 template<class T, class U> 268 T smart_cast_reference(U & u) { 269 return smart_cast_impl::reference< T >::cast(u); 270 } 271 272 } // namespace serialization 273 } // namespace boost 274 275 #endif // BOOST_SERIALIZATION_SMART_CAST_HPP 276