source: tags/arb-6.0/TEMPLATES/downcast.h

Last change on this file was 10564, checked in by westram, 11 years ago
  • fix gcc.4.8++ compilation for RNACMA (clash with boost namespace)
File size: 4.7 KB
Line 
1// =============================================================== //
2//                                                                 //
3//   File      : downcast.h                                        //
4//   Purpose   : safely cast from base class to derived class      //
5//                                                                 //
6//   Coded by Ralf Westram (coder@reallysoft.de) in October 2009   //
7//   Institute of Microbiology (Technical University Munich)       //
8//   http://www.arb-home.de/                                       //
9//                                                                 //
10// =============================================================== //
11
12#ifndef DOWNCAST_H
13#define DOWNCAST_H
14
15#ifndef ARB_ASSERT_H
16#include <arb_assert.h>
17#endif
18#ifndef STATIC_ASSERT_H
19#include "static_assert.h"
20#endif
21
22#if defined(DEBUG)
23#define SAFE_DOWNCASTS
24#endif // DEBUG
25
26// --------------------
27
28namespace ARB_type_traits { // according to boost-type_traits or std-type_traits
29                            // (remove when available in std for lowest supported gcc-version)
30    typedef char (&yes)[1];
31    typedef char (&no)[2];
32
33    template <typename B, typename D>
34    struct Host {
35        operator B*() const;
36        operator D*();
37    };
38
39    template <typename B, typename D>
40    struct is_base_of {
41        template <typename T> static yes check(D*, T);
42        static no check(B*, int);
43
44        static const bool value = sizeof(check(Host<B,D>(), int())) == sizeof(yes);
45    };
46
47    template <typename T, typename U>
48    struct is_same {
49        static T *t;
50        static U *u;
51
52        static yes check(T*, T*);
53        static no  check(...);
54
55        static const bool value = sizeof(check(t, u)) == sizeof(yes);
56    };
57
58    template< class T > struct remove_const          { typedef T type; };
59    template< class T > struct remove_const<const T> { typedef T type; };
60
61    template< class T > struct remove_volatile             { typedef T type; };
62    template< class T > struct remove_volatile<volatile T> { typedef T type; };
63
64    template< class T > struct remove_cv { typedef typename remove_volatile<typename remove_const<T>::type>::type type; };
65
66};
67
68// -----------------------------------------
69//      detect and deref pointer-types:
70
71
72template<typename> struct dereference {
73    static const bool possible = false;
74};
75template<typename T> struct dereference<T*> {
76    static const bool possible = true;
77    typedef T type;
78};
79template<typename T> struct dereference<T*const> {
80    static const bool possible = true;
81    typedef T type;
82};
83
84// ----------------------------------------------
85// DOWNCAST from DERIVED* to BASE*
86// - uses dynamic_cast in DEBUG mode and checks for failure
87// - uses plain old cast in NDEBUG mode
88
89#if defined(SAFE_DOWNCASTS)
90
91template<class DERIVED>
92inline DERIVED assert_downcasted(DERIVED expr) {
93    arb_assert(expr); // impossible DOWNCAST (expr is not of type DERIVED)
94    return expr;
95}
96
97template<class DERIVED, class BASE>
98inline DERIVED *safe_pointer_downcast(BASE *expr) {
99    STATIC_ASSERT_ANNOTATED(dereference<BASE   >::possible == false, "got BASE** (expected BASE*)");
100    STATIC_ASSERT_ANNOTATED(dereference<DERIVED>::possible == false, "got DERIVED** (expected DERIVED*)");
101
102    typedef typename ARB_type_traits::remove_cv<BASE   >::type NCV_BASE;
103    typedef typename ARB_type_traits::remove_cv<DERIVED>::type NCV_DERIVED;
104
105    STATIC_ASSERT_ANNOTATED((ARB_type_traits::is_base_of<BASE,DERIVED>::value ||
106                             ARB_type_traits::is_same<NCV_BASE, NCV_DERIVED>::value),
107                             "downcast only allowed from base type to derived type");
108
109    return expr
110        ? assert_downcasted<DERIVED*>(dynamic_cast<DERIVED*>(expr))
111        : NULL;
112}
113
114template<class DERIVED_PTR, class BASE_PTR>
115inline DERIVED_PTR safe_downcast(BASE_PTR expr) {
116    STATIC_ASSERT_ANNOTATED(dereference<BASE_PTR   >::possible == true, "expected 'BASE*' as source type");
117    STATIC_ASSERT_ANNOTATED(dereference<DERIVED_PTR>::possible == true, "expected 'DERIVED*' as target type");
118
119    typedef typename dereference<BASE_PTR   >::type BASE;
120    typedef typename dereference<DERIVED_PTR>::type DERIVED;
121
122    return safe_pointer_downcast<DERIVED,BASE>(expr);
123}
124
125#define DOWNCAST(totype,expr)      safe_downcast<totype,typeof(expr)>(expr)
126
127#else
128
129#define DOWNCAST(totype,expr)      ((totype)(expr))
130
131#endif // SAFE_DOWNCASTS
132
133
134// helper macro to overwrite accessor functions in derived classes
135#define DEFINE_DOWNCAST_ACCESSORS(CLASS, NAME, VALUE)                   \
136    CLASS *NAME() { return DOWNCAST(CLASS*, VALUE); }                   \
137    const CLASS *NAME() const { return DOWNCAST(const CLASS*, VALUE); }
138
139#else
140#error downcast.h included twice
141#endif // DOWNCAST_H
Note: See TracBrowser for help on using the repository browser.