smart_cast.hpp 8.7 KB

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