source: NonGTP/Boost/boost/smart_cast.hpp @ 857

Revision 857, 10.4 KB checked in by igarcia, 19 years ago (diff)
RevLine 
[857]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
58namespace boost {
59namespace 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)
263template<class T, class U>
264T 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)
291template<class T, class U>
292T 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
Note: See TracBrowser for help on using the repository browser.