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