| 1 | #ifndef BOOST_SMART_CAST_HPP | 
|---|
| 2 | #define BOOST_SMART_CAST_HPP | 
|---|
| 3 |  | 
|---|
| 4 | // MS compatible compilers support #pragma once | 
|---|
| 5 | #if defined(_MSC_VER) && (_MSC_VER >= 1020) | 
|---|
| 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 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 |  | 
|---|
| 40 | #include <boost/config.hpp> | 
|---|
| 41 | #include <boost/static_assert.hpp> | 
|---|
| 42 |  | 
|---|
| 43 | #include <boost/type_traits/is_base_and_derived.hpp> | 
|---|
| 44 | #include <boost/type_traits/is_polymorphic.hpp> | 
|---|
| 45 | #include <boost/type_traits/is_pointer.hpp> | 
|---|
| 46 | #include <boost/type_traits/is_reference.hpp> | 
|---|
| 47 | #include <boost/type_traits/is_same.hpp> | 
|---|
| 48 | #include <boost/type_traits/remove_pointer.hpp> | 
|---|
| 49 | #include <boost/type_traits/remove_reference.hpp> | 
|---|
| 50 |  | 
|---|
| 51 | #include <boost/mpl/eval_if.hpp> | 
|---|
| 52 | #include <boost/mpl/if.hpp> | 
|---|
| 53 | #include <boost/mpl/or.hpp> | 
|---|
| 54 | #include <boost/mpl/and.hpp> | 
|---|
| 55 | #include <boost/mpl/not.hpp> | 
|---|
| 56 | #include <boost/mpl/identity.hpp> | 
|---|
| 57 |  | 
|---|
| 58 | namespace boost { | 
|---|
| 59 | namespace smart_cast_impl { | 
|---|
| 60 |  | 
|---|
| 61 |     template<class T> | 
|---|
| 62 |     struct reference { | 
|---|
| 63 |  | 
|---|
| 64 |         struct polymorphic { | 
|---|
| 65 |  | 
|---|
| 66 |             struct linear { | 
|---|
| 67 |                 template<class U> | 
|---|
| 68 |                  static T cast(U & u){ | 
|---|
| 69 |                     return static_cast<T>(u); | 
|---|
| 70 |                 } | 
|---|
| 71 |             }; | 
|---|
| 72 |  | 
|---|
| 73 |             struct cross { | 
|---|
| 74 |                  template<class U> | 
|---|
| 75 |                 static T cast(U & u){ | 
|---|
| 76 |                     return dynamic_cast<T>(u); | 
|---|
| 77 |                 } | 
|---|
| 78 |             }; | 
|---|
| 79 |  | 
|---|
| 80 |             template<class U> | 
|---|
| 81 |             static T cast(U & u){ | 
|---|
| 82 |                 // if we're in debug mode | 
|---|
| 83 |                 #if ! defined(NDEBUG)                               \ | 
|---|
| 84 |                 || defined(__BORLANDC__) && (__BORLANDC__ <= 0x560) \ | 
|---|
| 85 |                 || defined(__MWERKS__) | 
|---|
| 86 |                     // do a checked dynamic cast | 
|---|
| 87 |                     return cross::cast(u); | 
|---|
| 88 |                 #else | 
|---|
| 89 |                     // borland 5.51 chokes here so we can't use it | 
|---|
| 90 |                     // note: if remove_reference isn't function for these types | 
|---|
| 91 |                     // cross casting will be selected this will work but will | 
|---|
| 92 |                     // not be the most efficient method. This will conflict with | 
|---|
| 93 |                     // the original smart_cast motivation. | 
|---|
| 94 |                     typedef BOOST_DEDUCED_TYPENAME mpl::eval_if< | 
|---|
| 95 |                             BOOST_DEDUCED_TYPENAME mpl::and_< | 
|---|
| 96 |                                 mpl::not_<is_base_and_derived< | 
|---|
| 97 |                                     BOOST_DEDUCED_TYPENAME remove_reference<T>::type, | 
|---|
| 98 |                                     U | 
|---|
| 99 |                                 > >, | 
|---|
| 100 |                                 mpl::not_<is_base_and_derived< | 
|---|
| 101 |                                     U, | 
|---|
| 102 |                                     BOOST_DEDUCED_TYPENAME remove_reference<T>::type | 
|---|
| 103 |                                 > > | 
|---|
| 104 |                             >, | 
|---|
| 105 |                             // borland chokes w/o full qualification here | 
|---|
| 106 |                             mpl::identity<cross>, | 
|---|
| 107 |                             mpl::identity<linear> | 
|---|
| 108 |                     >::type typex; | 
|---|
| 109 |                     // typex works around gcc 2.95 issue | 
|---|
| 110 |                     return typex::cast(u); | 
|---|
| 111 |                 #endif | 
|---|
| 112 |             } | 
|---|
| 113 |         }; | 
|---|
| 114 |  | 
|---|
| 115 |         struct non_polymorphic { | 
|---|
| 116 |             template<class U> | 
|---|
| 117 |              static T cast(U & u){ | 
|---|
| 118 |                 return static_cast<T>(u); | 
|---|
| 119 |             } | 
|---|
| 120 |         }; | 
|---|
| 121 |         template<class U> | 
|---|
| 122 |         static T cast(U & u){ | 
|---|
| 123 |             #if defined(__BORLANDC__) | 
|---|
| 124 |                 return mpl::eval_if< | 
|---|
| 125 |                     boost::is_polymorphic<U>, | 
|---|
| 126 |                     mpl::identity<polymorphic>, | 
|---|
| 127 |                     mpl::identity<non_polymorphic> | 
|---|
| 128 |                 >::type::cast(u); | 
|---|
| 129 |             #else | 
|---|
| 130 |                 typedef BOOST_DEDUCED_TYPENAME mpl::eval_if< | 
|---|
| 131 |                     boost::is_polymorphic<U>, | 
|---|
| 132 |                     mpl::identity<polymorphic>, | 
|---|
| 133 |                     mpl::identity<non_polymorphic> | 
|---|
| 134 |                 >::type typex; | 
|---|
| 135 |                 return typex::cast(u); | 
|---|
| 136 |             #endif | 
|---|
| 137 |         } | 
|---|
| 138 |     }; | 
|---|
| 139 |  | 
|---|
| 140 |     template<class T> | 
|---|
| 141 |     struct pointer { | 
|---|
| 142 |  | 
|---|
| 143 |         struct polymorphic { | 
|---|
| 144 |             // unfortunately, this below fails to work for virtual base  | 
|---|
| 145 |             // classes.  need has_virtual_base to do this. | 
|---|
| 146 |             // Subject for further study | 
|---|
| 147 |             #if 0 | 
|---|
| 148 |             struct linear { | 
|---|
| 149 |                 template<class U> | 
|---|
| 150 |                  static T cast(U * u){ | 
|---|
| 151 |                     return static_cast<T>(u); | 
|---|
| 152 |                 } | 
|---|
| 153 |             }; | 
|---|
| 154 |  | 
|---|
| 155 |             struct cross { | 
|---|
| 156 |                 template<class U> | 
|---|
| 157 |                 static T cast(U * u){ | 
|---|
| 158 |                     T tmp = dynamic_cast<T>(u); | 
|---|
| 159 |                     #ifndef NDEBUG | 
|---|
| 160 |                         if ( tmp == 0 ) throw std::bad_cast(); | 
|---|
| 161 |                     #endif | 
|---|
| 162 |                     return tmp; | 
|---|
| 163 |                 } | 
|---|
| 164 |             }; | 
|---|
| 165 |  | 
|---|
| 166 |             template<class U> | 
|---|
| 167 |             static T cast(U * u){ | 
|---|
| 168 |                 // if we're in debug mode | 
|---|
| 169 |                 #if ! defined(NDEBUG) || defined(__BORLANDC__) && (__BORLANDC__ <= 0x560) | 
|---|
| 170 |                     // do a checked dynamic cast | 
|---|
| 171 |                     return cross::cast(u); | 
|---|
| 172 |                 #else | 
|---|
| 173 |                     // borland 5.51 chokes here so we can't use it | 
|---|
| 174 |                     // note: if remove_pointer isn't function for these types | 
|---|
| 175 |                     // cross casting will be selected this will work but will | 
|---|
| 176 |                     // not be the most efficient method. This will conflict with | 
|---|
| 177 |                     // the original smart_cast motivation. | 
|---|
| 178 |                     typedef | 
|---|
| 179 |                         BOOST_DEDUCED_TYPENAME mpl::eval_if< | 
|---|
| 180 |                             BOOST_DEDUCED_TYPENAME mpl::and_< | 
|---|
| 181 |                                 mpl::not_<is_base_and_derived< | 
|---|
| 182 |                                     BOOST_DEDUCED_TYPENAME remove_pointer<T>::type, | 
|---|
| 183 |                                     U | 
|---|
| 184 |                                 > >, | 
|---|
| 185 |                                 mpl::not_<is_base_and_derived< | 
|---|
| 186 |                                     U, | 
|---|
| 187 |                                     BOOST_DEDUCED_TYPENAME remove_pointer<T>::type | 
|---|
| 188 |                                 > > | 
|---|
| 189 |                             >, | 
|---|
| 190 |                             // borland chokes w/o full qualification here | 
|---|
| 191 |                             mpl::identity<cross>, | 
|---|
| 192 |                             mpl::identity<linear> | 
|---|
| 193 |                         >::type typex; | 
|---|
| 194 |                     return typex::cast(u); | 
|---|
| 195 |                 #endif | 
|---|
| 196 |             } | 
|---|
| 197 |             #else | 
|---|
| 198 |             template<class U> | 
|---|
| 199 |             static T cast(U * u){ | 
|---|
| 200 |                 T tmp = dynamic_cast<T>(u); | 
|---|
| 201 |                 #ifndef NDEBUG | 
|---|
| 202 |                     if ( tmp == 0 ) throw std::bad_cast(); | 
|---|
| 203 |                 #endif | 
|---|
| 204 |                 return tmp; | 
|---|
| 205 |             } | 
|---|
| 206 |             #endif | 
|---|
| 207 |         }; | 
|---|
| 208 |  | 
|---|
| 209 |         struct non_polymorphic { | 
|---|
| 210 |             template<class U> | 
|---|
| 211 |              static T cast(U * u){ | 
|---|
| 212 |                 return static_cast<T>(u); | 
|---|
| 213 |             } | 
|---|
| 214 |         }; | 
|---|
| 215 |  | 
|---|
| 216 |         template<class U> | 
|---|
| 217 |         static T cast(U * u){ | 
|---|
| 218 |             #if defined(__BORLANDC__) | 
|---|
| 219 |                 return mpl::eval_if< | 
|---|
| 220 |                     boost::is_polymorphic<U>, | 
|---|
| 221 |                     mpl::identity<polymorphic>, | 
|---|
| 222 |                     mpl::identity<non_polymorphic> | 
|---|
| 223 |                 >::type::cast(u); | 
|---|
| 224 |             #else | 
|---|
| 225 |                 typedef BOOST_DEDUCED_TYPENAME mpl::eval_if< | 
|---|
| 226 |                     boost::is_polymorphic<U>, | 
|---|
| 227 |                     mpl::identity<polymorphic>, | 
|---|
| 228 |                     mpl::identity<non_polymorphic> | 
|---|
| 229 |                 >::type typex; | 
|---|
| 230 |                 return typex::cast(u); | 
|---|
| 231 |             #endif | 
|---|
| 232 |         } | 
|---|
| 233 |  | 
|---|
| 234 |     }; | 
|---|
| 235 |  | 
|---|
| 236 |     template<class TPtr> | 
|---|
| 237 |     struct void_pointer { | 
|---|
| 238 |         template<class UPtr> | 
|---|
| 239 |         static TPtr cast(UPtr uptr){ | 
|---|
| 240 |             return static_cast<TPtr>(uptr); | 
|---|
| 241 |         } | 
|---|
| 242 |     }; | 
|---|
| 243 |  | 
|---|
| 244 |     template<class T> | 
|---|
| 245 |     struct error { | 
|---|
| 246 |         // if we get here, its because we are using one argument in the | 
|---|
| 247 |         // cast on a system which doesn't support partial template  | 
|---|
| 248 |         // specialization | 
|---|
| 249 |         template<class U> | 
|---|
| 250 |         static T cast(U u){ | 
|---|
| 251 |             BOOST_STATIC_ASSERT(sizeof(T)==0); | 
|---|
| 252 |             return * static_cast<T *>(NULL); | 
|---|
| 253 |         } | 
|---|
| 254 |     }; | 
|---|
| 255 |  | 
|---|
| 256 | } // smart_cast_impl | 
|---|
| 257 |  | 
|---|
| 258 | // this implements: | 
|---|
| 259 | // smart_cast<Target *, Source *>(Source * s) | 
|---|
| 260 | // smart_cast<Target &, Source &>(s) | 
|---|
| 261 | // note that it will fail with | 
|---|
| 262 | // smart_cast<Target &>(s) | 
|---|
| 263 | template<class T, class U> | 
|---|
| 264 | T smart_cast(U u) { | 
|---|
| 265 |     typedef | 
|---|
| 266 |         BOOST_DEDUCED_TYPENAME mpl::eval_if< | 
|---|
| 267 |             BOOST_DEDUCED_TYPENAME mpl::or_< | 
|---|
| 268 |                 boost::is_same<void *, U>, | 
|---|
| 269 |                 boost::is_same<void *, T>, | 
|---|
| 270 |                 boost::is_same<const void *, U>, | 
|---|
| 271 |                 boost::is_same<const void *, T> | 
|---|
| 272 |             >, | 
|---|
| 273 |             mpl::identity<smart_cast_impl::void_pointer<T> >, | 
|---|
| 274 |         // else | 
|---|
| 275 |         BOOST_DEDUCED_TYPENAME mpl::eval_if<boost::is_pointer<U>, | 
|---|
| 276 |             mpl::identity<smart_cast_impl::pointer<T> >, | 
|---|
| 277 |         // else | 
|---|
| 278 |         BOOST_DEDUCED_TYPENAME mpl::eval_if<boost::is_reference<U>, | 
|---|
| 279 |             mpl::identity<smart_cast_impl::reference<T> >, | 
|---|
| 280 |         // else | 
|---|
| 281 |             mpl::identity<smart_cast_impl::error<T> | 
|---|
| 282 |         > | 
|---|
| 283 |         > | 
|---|
| 284 |         > | 
|---|
| 285 |         >::type typex; | 
|---|
| 286 |     return typex::cast(u); | 
|---|
| 287 | } | 
|---|
| 288 |  | 
|---|
| 289 | // this implements: | 
|---|
| 290 | // smart_cast_reference<Target &>(Source & s) | 
|---|
| 291 | template<class T, class U> | 
|---|
| 292 | T smart_cast_reference(U & u) { | 
|---|
| 293 |     return smart_cast_impl::reference<T>::cast(u); | 
|---|
| 294 | } | 
|---|
| 295 |  | 
|---|
| 296 | } // namespace boost | 
|---|
| 297 |  | 
|---|
| 298 | #endif // BOOST_SMART_CAST_HPP | 
|---|