| 1 | // ============================================================== // |
|---|
| 2 | // // |
|---|
| 3 | // File : ttypes.h // |
|---|
| 4 | // Purpose : template type inspection // |
|---|
| 5 | // // |
|---|
| 6 | // Coded by Ralf Westram (coder@reallysoft.de) in August 2011 // |
|---|
| 7 | // Institute of Microbiology (Technical University Munich) // |
|---|
| 8 | // http://www.arb-home.de/ // |
|---|
| 9 | // // |
|---|
| 10 | // ============================================================== // |
|---|
| 11 | |
|---|
| 12 | #ifndef TTYPES_H |
|---|
| 13 | #define TTYPES_H |
|---|
| 14 | |
|---|
| 15 | // according to C++ templates by Vandevoorde/Josuttis |
|---|
| 16 | // thank you for that great book |
|---|
| 17 | |
|---|
| 18 | #ifndef _GLIBCXX_CSTDLIB |
|---|
| 19 | #include <cstdlib> |
|---|
| 20 | #endif |
|---|
| 21 | |
|---|
| 22 | #define NOisnotYES() enum { No = !Yes } |
|---|
| 23 | |
|---|
| 24 | // -------------------------- |
|---|
| 25 | // fundamental types |
|---|
| 26 | |
|---|
| 27 | template<typename T> class IsFundaT { public: enum { Yes = 0, No = 1 }; }; |
|---|
| 28 | #define DECL_FUNDA_TYPE(t) template<> class IsFundaT<t> { public: enum { Yes = 1, No = 0 }; }; |
|---|
| 29 | #define DECL_FUNDA_TYPE_SIGNED(t) DECL_FUNDA_TYPE(signed t); DECL_FUNDA_TYPE(unsigned t) |
|---|
| 30 | |
|---|
| 31 | DECL_FUNDA_TYPE(bool); |
|---|
| 32 | DECL_FUNDA_TYPE(char); |
|---|
| 33 | DECL_FUNDA_TYPE_SIGNED(char); |
|---|
| 34 | DECL_FUNDA_TYPE_SIGNED(int); |
|---|
| 35 | DECL_FUNDA_TYPE_SIGNED(long); |
|---|
| 36 | DECL_FUNDA_TYPE_SIGNED(long long); |
|---|
| 37 | DECL_FUNDA_TYPE(float); |
|---|
| 38 | DECL_FUNDA_TYPE(double); |
|---|
| 39 | DECL_FUNDA_TYPE(long double); |
|---|
| 40 | |
|---|
| 41 | #undef DECL_FUNDA_TYPE_SIGNED |
|---|
| 42 | #undef DECL_FUNDA_TYPE |
|---|
| 43 | |
|---|
| 44 | // ----------------------- |
|---|
| 45 | // function types |
|---|
| 46 | |
|---|
| 47 | template<typename T> |
|---|
| 48 | class IsFunctionT { |
|---|
| 49 | private: |
|---|
| 50 | typedef char yes; |
|---|
| 51 | typedef struct { char a[2]; } no; |
|---|
| 52 | public: |
|---|
| 53 | template<typename U> static yes test(...); |
|---|
| 54 | template<typename U> static no test(U (*)[1]); |
|---|
| 55 | enum { Yes = sizeof(test<T>(0)) == sizeof(yes) }; |
|---|
| 56 | NOisnotYES(); |
|---|
| 57 | }; |
|---|
| 58 | |
|---|
| 59 | #define NO_FUNCTION_TYPE(t) class IsFunctionT<t> { public: enum { Yes = 0 }; NOisnotYES(); } |
|---|
| 60 | |
|---|
| 61 | template<typename T> NO_FUNCTION_TYPE(T&); |
|---|
| 62 | template<> NO_FUNCTION_TYPE(void); |
|---|
| 63 | template<> NO_FUNCTION_TYPE(void const); |
|---|
| 64 | template<> NO_FUNCTION_TYPE(void volatile); |
|---|
| 65 | template<> NO_FUNCTION_TYPE(void const volatile); |
|---|
| 66 | |
|---|
| 67 | #undef NO_FUNCTION_TYPE |
|---|
| 68 | |
|---|
| 69 | // ----------------------- |
|---|
| 70 | // compound types |
|---|
| 71 | |
|---|
| 72 | template<typename T> |
|---|
| 73 | struct CompountT { // primary template |
|---|
| 74 | enum { IsPtrT = 0, IsRefT = 0, IsArrayT = 0, IsFuncT = IsFunctionT<T>::Yes, IsPtrMemT = 0 }; |
|---|
| 75 | typedef T BaseT; |
|---|
| 76 | typedef T BottomT; |
|---|
| 77 | typedef CompountT<void> ClassT; |
|---|
| 78 | }; |
|---|
| 79 | template<typename T> |
|---|
| 80 | struct CompountT<T*> { // specialization for pointers |
|---|
| 81 | enum { IsPtrT = 1, IsRefT = 0, IsArrayT = 0, IsFuncT = 0, IsPtrMemT = 0 }; |
|---|
| 82 | typedef T BaseT; |
|---|
| 83 | typedef typename CompountT<T>::BottomT BottomT; |
|---|
| 84 | typedef CompountT<void> ClassT; |
|---|
| 85 | }; |
|---|
| 86 | template<typename T> |
|---|
| 87 | struct CompountT<T&> { // specialization for references |
|---|
| 88 | enum { IsPtrT = 0, IsRefT = 1, IsArrayT = 0, IsFuncT = 0, IsPtrMemT = 0 }; |
|---|
| 89 | typedef T BaseT; |
|---|
| 90 | typedef typename CompountT<T>::BottomT BottomT; |
|---|
| 91 | typedef CompountT<void> ClassT; |
|---|
| 92 | }; |
|---|
| 93 | template<typename T, size_t N> |
|---|
| 94 | struct CompountT<T[N]> { // specialization for arrays |
|---|
| 95 | enum { IsPtrT = 0, IsRefT = 0, IsArrayT = 1, IsFuncT = 0, IsPtrMemT = 0 }; |
|---|
| 96 | typedef T BaseT; |
|---|
| 97 | typedef typename CompountT<T>::BottomT BottomT; |
|---|
| 98 | typedef CompountT<void> ClassT; |
|---|
| 99 | }; |
|---|
| 100 | template<typename T> |
|---|
| 101 | struct CompountT<T[]> { // specialization for empty arrays |
|---|
| 102 | enum { IsPtrT = 0, IsRefT = 0, IsArrayT = 1, IsFuncT = 0, IsPtrMemT = 0 }; |
|---|
| 103 | typedef T BaseT; |
|---|
| 104 | typedef typename CompountT<T>::BottomT BottomT; |
|---|
| 105 | typedef CompountT<void> ClassT; |
|---|
| 106 | }; |
|---|
| 107 | template<typename T, typename C> |
|---|
| 108 | struct CompountT<T C::*> { // specialization for pointers to members |
|---|
| 109 | enum { IsPtrT = 0, IsRefT = 0, IsArrayT = 0, IsFuncT = 0, IsPtrMemT = 1 }; |
|---|
| 110 | typedef T BaseT; |
|---|
| 111 | typedef typename CompountT<T>::BottomT BottomT; |
|---|
| 112 | typedef C ClassT; |
|---|
| 113 | }; |
|---|
| 114 | |
|---|
| 115 | template<typename R> |
|---|
| 116 | struct CompountT<R()> { // specialization for functions () |
|---|
| 117 | enum { IsPtrT = 0, IsRefT = 0, IsArrayT = 0, IsFuncT = 1, IsPtrMemT = 0 }; |
|---|
| 118 | typedef R BaseT(); |
|---|
| 119 | typedef R BottomT(); |
|---|
| 120 | typedef CompountT<void> ClassT; |
|---|
| 121 | }; |
|---|
| 122 | template<typename R, typename P1> |
|---|
| 123 | struct CompountT<R(P1)> { // specialization for functions (P1) |
|---|
| 124 | enum { IsPtrT = 0, IsRefT = 0, IsArrayT = 0, IsFuncT = 1, IsPtrMemT = 0 }; |
|---|
| 125 | typedef R BaseT(P1); |
|---|
| 126 | typedef R BottomT(P1); |
|---|
| 127 | typedef CompountT<void> ClassT; |
|---|
| 128 | }; |
|---|
| 129 | template<typename R, typename P1> |
|---|
| 130 | struct CompountT<R(P1, ...)> { // specialization for functions (P1, ...) |
|---|
| 131 | enum { IsPtrT = 0, IsRefT = 0, IsArrayT = 0, IsFuncT = 1, IsPtrMemT = 0 }; |
|---|
| 132 | typedef R BaseT(P1); |
|---|
| 133 | typedef R BottomT(P1); |
|---|
| 134 | typedef CompountT<void> ClassT; |
|---|
| 135 | }; |
|---|
| 136 | |
|---|
| 137 | // ------------------- |
|---|
| 138 | // enum types |
|---|
| 139 | |
|---|
| 140 | struct SizeOverOne { char c[2]; }; |
|---|
| 141 | |
|---|
| 142 | template<typename T, bool convert_possible = !CompountT<T>::IsFuncT && !CompountT<T>::IsArrayT> |
|---|
| 143 | class ConsumeUDC { public: operator T() const; }; |
|---|
| 144 | |
|---|
| 145 | template<typename T> class ConsumeUDC<T, false> {}; // conversion to function types not possible |
|---|
| 146 | template<bool convert_possible> class ConsumeUDC<void, convert_possible> {}; // conversion to void not possible |
|---|
| 147 | |
|---|
| 148 | #define enum_check_SIGNED(t) char enum_check(signed t); char enum_check(unsigned t) |
|---|
| 149 | |
|---|
| 150 | char enum_check(bool); |
|---|
| 151 | enum_check_SIGNED(char); |
|---|
| 152 | char enum_check(wchar_t); |
|---|
| 153 | enum_check_SIGNED(short); |
|---|
| 154 | enum_check_SIGNED(int); |
|---|
| 155 | enum_check_SIGNED(long); |
|---|
| 156 | char enum_check(float); |
|---|
| 157 | char enum_check(double); |
|---|
| 158 | char enum_check(long double); |
|---|
| 159 | char enum_check(long long); |
|---|
| 160 | |
|---|
| 161 | #undef enum_check_SIGNED |
|---|
| 162 | |
|---|
| 163 | SizeOverOne enum_check(...); // catch all |
|---|
| 164 | |
|---|
| 165 | template<typename T> |
|---|
| 166 | struct IsEnumT { |
|---|
| 167 | enum { |
|---|
| 168 | Yes = IsFundaT<T>::No && |
|---|
| 169 | !CompountT<T>::IsPtrT && |
|---|
| 170 | !CompountT<T>::IsRefT && |
|---|
| 171 | !CompountT<T>::IsPtrMemT && |
|---|
| 172 | sizeof(enum_check(ConsumeUDC<T>())) == 1 |
|---|
| 173 | }; |
|---|
| 174 | NOisnotYES(); |
|---|
| 175 | }; |
|---|
| 176 | |
|---|
| 177 | // -------------------- |
|---|
| 178 | // class types |
|---|
| 179 | |
|---|
| 180 | template<typename T> |
|---|
| 181 | struct IsClassT { |
|---|
| 182 | enum { |
|---|
| 183 | Yes = IsFundaT<T>::No && |
|---|
| 184 | IsEnumT<T>::No && |
|---|
| 185 | !CompountT<T>::IsPtrT && |
|---|
| 186 | !CompountT<T>::IsRefT && |
|---|
| 187 | !CompountT<T>::IsArrayT && |
|---|
| 188 | !CompountT<T>::IsPtrMemT && |
|---|
| 189 | !CompountT<T>::IsFuncT |
|---|
| 190 | }; |
|---|
| 191 | NOisnotYES(); |
|---|
| 192 | }; |
|---|
| 193 | |
|---|
| 194 | // --------------------------- |
|---|
| 195 | // generic type check |
|---|
| 196 | |
|---|
| 197 | template<typename T> |
|---|
| 198 | struct TypeT { |
|---|
| 199 | enum { |
|---|
| 200 | IsFundaT = IsFundaT<T>::Yes, |
|---|
| 201 | IsPtrT = CompountT<T>::IsPtrT, |
|---|
| 202 | IsRefT = CompountT<T>::IsRefT, |
|---|
| 203 | IsArrayT = CompountT<T>::IsArrayT, |
|---|
| 204 | IsFuncT = CompountT<T>::IsFuncT, |
|---|
| 205 | IsPtrMemT = CompountT<T>::IsPtrMemT, |
|---|
| 206 | IsEnumT = IsEnumT<T>::Yes, |
|---|
| 207 | IsClassT = IsClassT<T>::Yes |
|---|
| 208 | }; |
|---|
| 209 | }; |
|---|
| 210 | |
|---|
| 211 | |
|---|
| 212 | // ---------------------- |
|---|
| 213 | // modify types |
|---|
| 214 | |
|---|
| 215 | |
|---|
| 216 | template<typename T> |
|---|
| 217 | struct TypeOp { // primary template |
|---|
| 218 | typedef T ArgT; |
|---|
| 219 | typedef T BareT; |
|---|
| 220 | typedef T const ConstT; |
|---|
| 221 | typedef T & RefT; |
|---|
| 222 | typedef T & RefBareT; |
|---|
| 223 | typedef T const & RefConstT; |
|---|
| 224 | }; |
|---|
| 225 | template<typename T> |
|---|
| 226 | struct TypeOp<T const> { // partial specialization for const types |
|---|
| 227 | typedef T const ArgT; |
|---|
| 228 | typedef T BareT; |
|---|
| 229 | typedef T const ConstT; |
|---|
| 230 | typedef T const & RefT; |
|---|
| 231 | typedef T & RefBareT; |
|---|
| 232 | typedef T const & RefConstT; |
|---|
| 233 | }; |
|---|
| 234 | template<typename T> |
|---|
| 235 | struct TypeOp<T&> { // partial specialization for references |
|---|
| 236 | typedef T & ArgT; |
|---|
| 237 | typedef typename TypeOp<T>::BareT BareT; |
|---|
| 238 | typedef T const ConstT; |
|---|
| 239 | typedef T & RefT; |
|---|
| 240 | typedef typename TypeOp<T>::BareT & RefBareT; |
|---|
| 241 | typedef T const & RefConstT; |
|---|
| 242 | }; |
|---|
| 243 | template<> |
|---|
| 244 | struct TypeOp<void> { // full specialization for void |
|---|
| 245 | typedef void ArgT; |
|---|
| 246 | typedef void BareT; |
|---|
| 247 | typedef void const ConstT; |
|---|
| 248 | typedef void RefT; |
|---|
| 249 | typedef void RefBareT; |
|---|
| 250 | typedef void RefConstT; |
|---|
| 251 | }; |
|---|
| 252 | |
|---|
| 253 | // ------------------------- |
|---|
| 254 | // conditional type |
|---|
| 255 | |
|---|
| 256 | template<bool B, typename T, typename F> class IfThenElseType; |
|---|
| 257 | template<typename T, typename F> class IfThenElseType<true, T, F> { public: typedef T ResultType; }; |
|---|
| 258 | template<typename T, typename F> class IfThenElseType<false, T, F> { public: typedef F ResultType; }; |
|---|
| 259 | |
|---|
| 260 | #undef NOisnotYES |
|---|
| 261 | |
|---|
| 262 | #else |
|---|
| 263 | #error ttypes.h included twice |
|---|
| 264 | #endif // TTYPES_H |
|---|