fix doc example typo
[boost.git] / boost / serialization / smart_cast.hpp
blob89a79c4068b6e42dfa1808275ecdea3e2b9acef1
1 #ifndef BOOST_SERIALIZATION_SMART_CAST_HPP
2 #define BOOST_SERIALIZATION_SMART_CAST_HPP
4 // MS compatible compilers support #pragma once
5 #if defined(_MSC_VER) && (_MSC_VER >= 1020)
6 # pragma once
7 #endif
9 /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
10 // smart_cast.hpp:
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)
17 // See http://www.boost.org/libs/serialization for updates, documentation, and revision history.
19 // casting of pointers and references.
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.
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.
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.
34 // smart_cast uses C++ type_traits, and program debug mode to select the
35 // most convenient cast to use.
37 #include <exception>
38 #include <typeinfo>
39 #include <cstddef> // NULL
41 #include <boost/config.hpp>
42 #include <boost/static_assert.hpp>
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>
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>
59 namespace boost {
60 namespace serialization {
61 namespace smart_cast_impl {
63 template<class T>
64 struct reference {
66 struct polymorphic {
68 struct linear {
69 template<class U>
70 static T cast(U & u){
71 return static_cast<T>(u);
75 struct cross {
76 template<class U>
77 static T cast(U & u){
78 return dynamic_cast<T>(u);
82 template<class U>
83 static T cast(U & u){
84 // if we're in debug mode
85 #if ! defined(NDEBUG) \
86 || defined(__BORLANDC__) && (__BORLANDC__ <= 0x560) \
87 || defined(__MWERKS__)
88 // do a checked dynamic cast
89 return cross::cast(u);
90 #else
91 // borland 5.51 chokes here so we can't use it
92 // note: if remove_reference isn't function for these types
93 // cross casting will be selected this will work but will
94 // not be the most efficient method. This will conflict with
95 // the original smart_cast motivation.
96 typedef BOOST_DEDUCED_TYPENAME mpl::eval_if<
97 BOOST_DEDUCED_TYPENAME mpl::and_<
98 mpl::not_<is_base_and_derived<
99 BOOST_DEDUCED_TYPENAME remove_reference<T>::type,
101 > >,
102 mpl::not_<is_base_and_derived<
104 BOOST_DEDUCED_TYPENAME remove_reference<T>::type
107 // borland chokes w/o full qualification here
108 mpl::identity<cross>,
109 mpl::identity<linear>
110 >::type typex;
111 // typex works around gcc 2.95 issue
112 return typex::cast(u);
113 #endif
117 struct non_polymorphic {
118 template<class U>
119 static T cast(U & u){
120 return static_cast<T>(u);
123 template<class U>
124 static T cast(U & u){
125 #if defined(__BORLANDC__)
126 return mpl::eval_if<
127 boost::is_polymorphic<U>,
128 mpl::identity<polymorphic>,
129 mpl::identity<non_polymorphic>
130 >::type::cast(u);
131 #else
132 typedef BOOST_DEDUCED_TYPENAME mpl::eval_if<
133 boost::is_polymorphic<U>,
134 mpl::identity<polymorphic>,
135 mpl::identity<non_polymorphic>
136 >::type typex;
137 return typex::cast(u);
138 #endif
142 template<class T>
143 struct pointer {
145 struct polymorphic {
146 // unfortunately, this below fails to work for virtual base
147 // classes. need has_virtual_base to do this.
148 // Subject for further study
149 #if 0
150 struct linear {
151 template<class U>
152 static T cast(U * u){
153 return static_cast<T>(u);
157 struct cross {
158 template<class U>
159 static T cast(U * u){
160 T tmp = dynamic_cast<T>(u);
161 #ifndef NDEBUG
162 if ( tmp == 0 ) throw std::bad_cast();
163 #endif
164 return tmp;
168 template<class U>
169 static T cast(U * u){
170 // if we're in debug mode
171 #if ! defined(NDEBUG) || defined(__BORLANDC__) && (__BORLANDC__ <= 0x560)
172 // do a checked dynamic cast
173 return cross::cast(u);
174 #else
175 // borland 5.51 chokes here so we can't use it
176 // note: if remove_pointer isn't function for these types
177 // cross casting will be selected this will work but will
178 // not be the most efficient method. This will conflict with
179 // the original smart_cast motivation.
180 typedef
181 BOOST_DEDUCED_TYPENAME mpl::eval_if<
182 BOOST_DEDUCED_TYPENAME mpl::and_<
183 mpl::not_<is_base_and_derived<
184 BOOST_DEDUCED_TYPENAME remove_pointer<T>::type,
186 > >,
187 mpl::not_<is_base_and_derived<
189 BOOST_DEDUCED_TYPENAME remove_pointer<T>::type
192 // borland chokes w/o full qualification here
193 mpl::identity<cross>,
194 mpl::identity<linear>
195 >::type typex;
196 return typex::cast(u);
197 #endif
199 #else
200 template<class U>
201 static T cast(U * u){
202 T tmp = dynamic_cast<T>(u);
203 #ifndef NDEBUG
204 if ( tmp == 0 ) throw std::bad_cast();
205 #endif
206 return tmp;
208 #endif
211 struct non_polymorphic {
212 template<class U>
213 static T cast(U * u){
214 return static_cast<T>(u);
218 template<class U>
219 static T cast(U * u){
220 #if defined(__BORLANDC__)
221 return mpl::eval_if<
222 boost::is_polymorphic<U>,
223 mpl::identity<polymorphic>,
224 mpl::identity<non_polymorphic>
225 >::type::cast(u);
226 #else
227 typedef BOOST_DEDUCED_TYPENAME mpl::eval_if<
228 boost::is_polymorphic<U>,
229 mpl::identity<polymorphic>,
230 mpl::identity<non_polymorphic>
231 >::type typex;
232 return typex::cast(u);
233 #endif
238 template<class TPtr>
239 struct void_pointer {
240 template<class UPtr>
241 static TPtr cast(UPtr uptr){
242 return static_cast<TPtr>(uptr);
246 template<class T>
247 struct error {
248 // if we get here, its because we are using one argument in the
249 // cast on a system which doesn't support partial template
250 // specialization
251 template<class U>
252 static T cast(U u){
253 BOOST_STATIC_ASSERT(sizeof(T)==0);
254 return * static_cast<T *>(NULL);
258 } // smart_cast_impl
260 // this implements:
261 // smart_cast<Target *, Source *>(Source * s)
262 // smart_cast<Target &, Source &>(s)
263 // note that it will fail with
264 // smart_cast<Target &>(s)
265 template<class T, class U>
266 T smart_cast(U u) {
267 typedef
268 BOOST_DEDUCED_TYPENAME mpl::eval_if<
269 BOOST_DEDUCED_TYPENAME mpl::or_<
270 boost::is_same<void *, U>,
271 boost::is_same<void *, T>,
272 boost::is_same<const void *, U>,
273 boost::is_same<const void *, T>
275 mpl::identity<smart_cast_impl::void_pointer<T> >,
276 // else
277 BOOST_DEDUCED_TYPENAME mpl::eval_if<boost::is_pointer<U>,
278 mpl::identity<smart_cast_impl::pointer<T> >,
279 // else
280 BOOST_DEDUCED_TYPENAME mpl::eval_if<boost::is_reference<U>,
281 mpl::identity<smart_cast_impl::reference<T> >,
282 // else
283 mpl::identity<smart_cast_impl::error<T>
287 >::type typex;
288 return typex::cast(u);
291 // this implements:
292 // smart_cast_reference<Target &>(Source & s)
293 template<class T, class U>
294 T smart_cast_reference(U & u) {
295 return smart_cast_impl::reference<T>::cast(u);
298 } // namespace serialization
299 } // namespace boost
301 #endif // BOOST_SERIALIZATION_SMART_CAST_HPP