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