1 #ifndef BOOST_SMART_CAST_HPP
2 #define BOOST_SMART_CAST_HPP
4 // MS compatible compilers support #pragma once
5 #if defined(_MSC_VER) && (_MSC_VER >= 1020)
9 /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
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 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.
40 #include <boost/config.hpp>
41 #include <boost/static_assert.hpp>
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>
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>
59 namespace smart_cast_impl {
69 return static_cast<T>(u);
76 return dynamic_cast<T>(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);
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,
100 mpl::not_<is_base_and_derived<
102 BOOST_DEDUCED_TYPENAME remove_reference<T>::type
105 // borland chokes w/o full qualification here
106 mpl::identity<cross>,
107 mpl::identity<linear>
109 // typex works around gcc 2.95 issue
110 return typex::cast(u);
115 struct non_polymorphic {
117 static T cast(U & u){
118 return static_cast<T>(u);
122 static T cast(U & u){
123 #if defined(__BORLANDC__)
125 boost::is_polymorphic<U>,
126 mpl::identity<polymorphic>,
127 mpl::identity<non_polymorphic>
130 typedef BOOST_DEDUCED_TYPENAME mpl::eval_if<
131 boost::is_polymorphic<U>,
132 mpl::identity<polymorphic>,
133 mpl::identity<non_polymorphic>
135 return typex::cast(u);
144 // unfortunately, this below fails to work for virtual base
145 // classes. need has_virtual_base to do this.
146 // Subject for further study
150 static T cast(U * u){
151 return static_cast<T>(u);
157 static T cast(U * u){
158 T tmp = dynamic_cast<T>(u);
160 if ( tmp == 0 ) throw std::bad_cast();
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);
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.
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,
185 mpl::not_<is_base_and_derived<
187 BOOST_DEDUCED_TYPENAME remove_pointer<T>::type
190 // borland chokes w/o full qualification here
191 mpl::identity<cross>,
192 mpl::identity<linear>
194 return typex::cast(u);
199 static T cast(U * u){
200 T tmp = dynamic_cast<T>(u);
202 if ( tmp == 0 ) throw std::bad_cast();
209 struct non_polymorphic {
211 static T cast(U * u){
212 return static_cast<T>(u);
217 static T cast(U * u){
218 #if defined(__BORLANDC__)
220 boost::is_polymorphic<U>,
221 mpl::identity<polymorphic>,
222 mpl::identity<non_polymorphic>
225 typedef BOOST_DEDUCED_TYPENAME mpl::eval_if<
226 boost::is_polymorphic<U>,
227 mpl::identity<polymorphic>,
228 mpl::identity<non_polymorphic>
230 return typex::cast(u);
237 struct void_pointer {
239 static TPtr cast(UPtr uptr){
240 return static_cast<TPtr>(uptr);
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
251 BOOST_STATIC_ASSERT(sizeof(T)==0);
252 return * static_cast<T *>(NULL);
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>
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>
273 mpl::identity<smart_cast_impl::void_pointer<T> >,
275 BOOST_DEDUCED_TYPENAME mpl::eval_if<boost::is_pointer<U>,
276 mpl::identity<smart_cast_impl::pointer<T> >,
278 BOOST_DEDUCED_TYPENAME mpl::eval_if<boost::is_reference<U>,
279 mpl::identity<smart_cast_impl::reference<T> >,
281 mpl::identity<smart_cast_impl::error<T>
286 return typex::cast(u);
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);
298 #endif // BOOST_SMART_CAST_HPP