Jeff Thompson | 86b6d64 | 2013-10-17 15:01:56 -0700 | [diff] [blame] | 1 | // scoped_enum_emulation.hpp ---------------------------------------------------------// |
| 2 | |
| 3 | // Copyright Beman Dawes, 2009 |
| 4 | // Copyright (C) 2011-2012 Vicente J. Botet Escriba |
| 5 | // Copyright (C) 2012 Anthony Williams |
| 6 | |
| 7 | // Distributed under the Boost Software License, Version 1.0. |
| 8 | // See http://www.boost.org/LICENSE_1_0.txt |
| 9 | |
| 10 | /* |
| 11 | [section:scoped_enums Scoped Enums] |
| 12 | |
| 13 | Generates C++0x scoped enums if the feature is present, otherwise emulates C++0x |
| 14 | scoped enums with C++03 namespaces and enums. The Boost.Config NDNBOOST_NO_CXX11_SCOPED_ENUMS |
| 15 | macro is used to detect feature support. |
| 16 | |
| 17 | See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2347.pdf for a |
| 18 | description of the scoped enum feature. Note that the committee changed the name |
| 19 | from strongly typed enum to scoped enum. |
| 20 | |
| 21 | Some of the enumerations defined in the standard library are scoped enums. |
| 22 | |
| 23 | enum class future_errc |
| 24 | { |
| 25 | broken_promise, |
| 26 | future_already_retrieved, |
| 27 | promise_already_satisfied, |
| 28 | no_state |
| 29 | }; |
| 30 | |
| 31 | On compilers that don't support them, the library provides two emulations: |
| 32 | |
| 33 | [heading Strict] |
| 34 | |
| 35 | * Able to specify the underlying type. |
| 36 | * explicit conversion to/from underlying type. |
| 37 | * The wrapper is not a C++03 enum type. |
| 38 | |
| 39 | The user can declare declare these types as |
| 40 | |
| 41 | NDNBOOST_SCOPED_ENUM_DECLARE_BEGIN(future_errc) |
| 42 | { |
| 43 | broken_promise, |
| 44 | future_already_retrieved, |
| 45 | promise_already_satisfied, |
| 46 | no_state |
| 47 | } |
| 48 | NDNBOOST_SCOPED_ENUM_DECLARE_END(future_errc) |
| 49 | |
| 50 | These macros allows to use 'future_errc' in almost all the cases as an scoped enum. |
| 51 | |
| 52 | future_errc err = future_errc::no_state; |
| 53 | |
| 54 | There are however some limitations: |
| 55 | |
| 56 | * The type is not a C++ enum, so 'is_enum<future_errc>' will be false_type. |
| 57 | * The emulated scoped enum can not be used in switch nor in template arguments. For these cases the user needs to use some macros. |
| 58 | |
| 59 | Instead of |
| 60 | |
| 61 | switch (ev) |
| 62 | { |
| 63 | case future_errc::broken_promise: |
| 64 | // ... |
| 65 | |
| 66 | use |
| 67 | |
| 68 | switch (ndnboost::native_value(ev)) |
| 69 | { |
| 70 | case future_errc::broken_promise: |
| 71 | |
| 72 | And instead of |
| 73 | |
| 74 | #ifdef NDNBOOST_NO_CXX11_SCOPED_ENUMS |
| 75 | template <> |
| 76 | struct NDNBOOST_SYMBOL_VISIBLE is_error_code_enum<future_errc> : public true_type { }; |
| 77 | #endif |
| 78 | |
| 79 | use |
| 80 | |
| 81 | #ifdef NDNBOOST_NO_CXX11_SCOPED_ENUMS |
| 82 | template <> |
| 83 | struct NDNBOOST_SYMBOL_VISIBLE is_error_code_enum<future_errc::enum_type > : public true_type { }; |
| 84 | #endif |
| 85 | |
| 86 | |
| 87 | Sample usage: |
| 88 | |
| 89 | NDNBOOST_SCOPED_ENUM_UT_DECLARE_BEGIN(algae, char) { green, red, cyan }; NDNBOOST_SCOPED_ENUM_DECLARE_END(algae) |
| 90 | ... |
| 91 | algae sample( algae::red ); |
| 92 | void foo( algae color ); |
| 93 | ... |
| 94 | sample = algae::green; |
| 95 | foo( algae::cyan ); |
| 96 | |
| 97 | Light |
| 98 | Caution: only the syntax is emulated; the semantics are not emulated and |
| 99 | the syntax emulation doesn't include being able to specify the underlying |
| 100 | representation type. |
| 101 | |
| 102 | The literal scoped emulation is via struct rather than namespace to allow use within classes. |
| 103 | Thanks to Andrey Semashev for pointing that out. |
| 104 | However the type is an real C++03 enum and so convertible implicitly to an int. |
| 105 | |
| 106 | Sample usage: |
| 107 | |
| 108 | NDNBOOST_SCOPED_ENUM_START(algae) { green, red, cyan }; NDNBOOST_SCOPED_ENUM_END |
| 109 | ... |
| 110 | NDNBOOST_SCOPED_ENUM(algae) sample( algae::red ); |
| 111 | void foo( NDNBOOST_SCOPED_ENUM(algae) color ); |
| 112 | ... |
| 113 | sample = algae::green; |
| 114 | foo( algae::cyan ); |
| 115 | |
| 116 | Helpful comments and suggestions were also made by Kjell Elster, Phil Endecott, |
| 117 | Joel Falcou, Mathias Gaunard, Felipe Magno de Almeida, Matt Calabrese, Vicente |
| 118 | Botet, and Daniel James. |
| 119 | |
| 120 | [endsect] |
| 121 | */ |
| 122 | |
| 123 | |
| 124 | #ifndef NDNBOOST_SCOPED_ENUM_EMULATION_HPP |
| 125 | #define NDNBOOST_SCOPED_ENUM_EMULATION_HPP |
| 126 | |
| 127 | #include <ndnboost/config.hpp> |
| 128 | #include <ndnboost/detail/workaround.hpp> |
| 129 | |
| 130 | namespace ndnboost |
| 131 | { |
| 132 | |
| 133 | #ifdef NDNBOOST_NO_CXX11_SCOPED_ENUMS |
| 134 | /** |
| 135 | * Meta-function to get the underlying type of a scoped enum. |
| 136 | * |
| 137 | * Requires EnumType must be an enum type or the emulation of a scoped enum |
| 138 | */ |
| 139 | template <typename EnumType> |
| 140 | struct underlying_type |
| 141 | { |
| 142 | /** |
| 143 | * The member typedef type names the underlying type of EnumType. It is EnumType::underlying_type when the EnumType is an emulated scoped enum, |
| 144 | * std::underlying_type<EnumType>::type when the standard library std::underlying_type is provided. |
| 145 | * |
| 146 | * The user will need to specialize it when the compiler supports scoped enums but don't provides std::underlying_type. |
| 147 | */ |
| 148 | typedef typename EnumType::underlying_type type; |
| 149 | }; |
| 150 | |
| 151 | /** |
| 152 | * Meta-function to get the native enum type associated to an enum class or its emulation. |
| 153 | */ |
| 154 | template <typename EnumType> |
| 155 | struct native_type |
| 156 | { |
| 157 | /** |
| 158 | * The member typedef type names the native enum type associated to the scoped enum, |
| 159 | * which is it self if the compiler supports scoped enums or EnumType::enum_type if it is an emulated scoped enum. |
| 160 | */ |
| 161 | typedef typename EnumType::enum_type type; |
| 162 | }; |
| 163 | |
| 164 | /** |
| 165 | * Casts a scoped enum to its underlying type. |
| 166 | * |
| 167 | * This function is useful when working with scoped enum classes, which doens't implicitly convert to the underlying type. |
| 168 | * @param v A scoped enum. |
| 169 | * @returns The underlying type. |
| 170 | * @throws No-throws. |
| 171 | */ |
| 172 | template <typename UnderlyingType, typename EnumType> |
| 173 | UnderlyingType underlying_cast(EnumType v) |
| 174 | { |
| 175 | return v.get_underlying_value_(); |
| 176 | } |
| 177 | |
| 178 | /** |
| 179 | * Casts a scoped enum to its native enum type. |
| 180 | * |
| 181 | * This function is useful to make programs portable when the scoped enum emulation can not be use where native enums can. |
| 182 | * |
| 183 | * EnumType the scoped enum type |
| 184 | * |
| 185 | * @param v A scoped enum. |
| 186 | * @returns The native enum value. |
| 187 | * @throws No-throws. |
| 188 | */ |
| 189 | template <typename EnumType> |
| 190 | inline |
| 191 | typename EnumType::enum_type native_value(EnumType e) |
| 192 | { |
| 193 | return e.native_value_(); |
| 194 | } |
| 195 | |
| 196 | #else // NDNBOOST_NO_CXX11_SCOPED_ENUMS |
| 197 | |
| 198 | template <typename EnumType> |
| 199 | struct underlying_type |
| 200 | { |
| 201 | //typedef typename std::underlying_type<EnumType>::type type; |
| 202 | }; |
| 203 | |
| 204 | template <typename EnumType> |
| 205 | struct native_type |
| 206 | { |
| 207 | typedef EnumType type; |
| 208 | }; |
| 209 | |
| 210 | template <typename UnderlyingType, typename EnumType> |
| 211 | UnderlyingType underlying_cast(EnumType v) |
| 212 | { |
| 213 | return static_cast<UnderlyingType>(v); |
| 214 | } |
| 215 | |
| 216 | template <typename EnumType> |
| 217 | inline |
| 218 | EnumType native_value(EnumType e) |
| 219 | { |
| 220 | return e; |
| 221 | } |
| 222 | |
| 223 | #endif |
| 224 | } |
| 225 | |
| 226 | |
| 227 | #ifdef NDNBOOST_NO_CXX11_SCOPED_ENUMS |
| 228 | |
| 229 | #ifndef NDNBOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS |
| 230 | |
| 231 | #define NDNBOOST_SCOPED_ENUM_UT_DECLARE_CONVERSION_OPERATOR \ |
| 232 | explicit operator underlying_type() const { return get_underlying_value_(); } |
| 233 | |
| 234 | #else |
| 235 | |
| 236 | #define NDNBOOST_SCOPED_ENUM_UT_DECLARE_CONVERSION_OPERATOR |
| 237 | |
| 238 | #endif |
| 239 | |
| 240 | /** |
| 241 | * Start a declaration of a scoped enum. |
| 242 | * |
| 243 | * @param EnumType The new scoped enum. |
| 244 | * @param UnderlyingType The underlying type. |
| 245 | */ |
| 246 | #define NDNBOOST_SCOPED_ENUM_UT_DECLARE_BEGIN(EnumType, UnderlyingType) \ |
| 247 | struct EnumType { \ |
| 248 | typedef UnderlyingType underlying_type; \ |
| 249 | EnumType() NDNBOOST_NOEXCEPT {} \ |
| 250 | explicit EnumType(underlying_type v) : v_(v) {} \ |
| 251 | underlying_type get_underlying_value_() const { return v_; } \ |
| 252 | NDNBOOST_SCOPED_ENUM_UT_DECLARE_CONVERSION_OPERATOR \ |
| 253 | private: \ |
| 254 | underlying_type v_; \ |
| 255 | typedef EnumType self_type; \ |
| 256 | public: \ |
| 257 | enum enum_type |
| 258 | |
| 259 | #define NDNBOOST_SCOPED_ENUM_DECLARE_END2() \ |
| 260 | enum_type get_native_value_() const NDNBOOST_NOEXCEPT { return enum_type(v_); } \ |
| 261 | operator enum_type() const NDNBOOST_NOEXCEPT { return get_native_value_(); } \ |
| 262 | friend bool operator ==(self_type lhs, self_type rhs) NDNBOOST_NOEXCEPT { return enum_type(lhs.v_)==enum_type(rhs.v_); } \ |
| 263 | friend bool operator ==(self_type lhs, enum_type rhs) NDNBOOST_NOEXCEPT { return enum_type(lhs.v_)==rhs; } \ |
| 264 | friend bool operator ==(enum_type lhs, self_type rhs) NDNBOOST_NOEXCEPT { return lhs==enum_type(rhs.v_); } \ |
| 265 | friend bool operator !=(self_type lhs, self_type rhs) NDNBOOST_NOEXCEPT { return enum_type(lhs.v_)!=enum_type(rhs.v_); } \ |
| 266 | friend bool operator !=(self_type lhs, enum_type rhs) NDNBOOST_NOEXCEPT { return enum_type(lhs.v_)!=rhs; } \ |
| 267 | friend bool operator !=(enum_type lhs, self_type rhs) NDNBOOST_NOEXCEPT { return lhs!=enum_type(rhs.v_); } \ |
| 268 | friend bool operator <(self_type lhs, self_type rhs) NDNBOOST_NOEXCEPT { return enum_type(lhs.v_)<enum_type(rhs.v_); } \ |
| 269 | friend bool operator <(self_type lhs, enum_type rhs) NDNBOOST_NOEXCEPT { return enum_type(lhs.v_)<rhs; } \ |
| 270 | friend bool operator <(enum_type lhs, self_type rhs) NDNBOOST_NOEXCEPT { return lhs<enum_type(rhs.v_); } \ |
| 271 | friend bool operator <=(self_type lhs, self_type rhs) NDNBOOST_NOEXCEPT { return enum_type(lhs.v_)<=enum_type(rhs.v_); } \ |
| 272 | friend bool operator <=(self_type lhs, enum_type rhs) NDNBOOST_NOEXCEPT { return enum_type(lhs.v_)<=rhs; } \ |
| 273 | friend bool operator <=(enum_type lhs, self_type rhs) NDNBOOST_NOEXCEPT { return lhs<=enum_type(rhs.v_); } \ |
| 274 | friend bool operator >(self_type lhs, self_type rhs) NDNBOOST_NOEXCEPT { return enum_type(lhs.v_)>enum_type(rhs.v_); } \ |
| 275 | friend bool operator >(self_type lhs, enum_type rhs) NDNBOOST_NOEXCEPT { return enum_type(lhs.v_)>rhs; } \ |
| 276 | friend bool operator >(enum_type lhs, self_type rhs) NDNBOOST_NOEXCEPT { return lhs>enum_type(rhs.v_); } \ |
| 277 | friend bool operator >=(self_type lhs, self_type rhs) NDNBOOST_NOEXCEPT { return enum_type(lhs.v_)>=enum_type(rhs.v_); } \ |
| 278 | friend bool operator >=(self_type lhs, enum_type rhs) NDNBOOST_NOEXCEPT { return enum_type(lhs.v_)>=rhs; } \ |
| 279 | friend bool operator >=(enum_type lhs, self_type rhs) NDNBOOST_NOEXCEPT { return lhs>=enum_type(rhs.v_); } \ |
| 280 | }; |
| 281 | |
| 282 | #define NDNBOOST_SCOPED_ENUM_DECLARE_END(EnumType) \ |
| 283 | ; \ |
| 284 | EnumType(enum_type v) NDNBOOST_NOEXCEPT : v_(v) {} \ |
| 285 | NDNBOOST_SCOPED_ENUM_DECLARE_END2() |
| 286 | |
| 287 | /** |
| 288 | * Starts a declaration of a scoped enum with the default int underlying type. |
| 289 | * |
| 290 | * @param EnumType The new scoped enum. |
| 291 | */ |
| 292 | #define NDNBOOST_SCOPED_ENUM_DECLARE_BEGIN(EnumType) \ |
| 293 | NDNBOOST_SCOPED_ENUM_UT_DECLARE_BEGIN(EnumType,int) |
| 294 | |
| 295 | /** |
| 296 | * Name of the native enum type. |
| 297 | * |
| 298 | * @param NT The new scoped enum. |
| 299 | */ |
| 300 | #define NDNBOOST_SCOPED_ENUM_NATIVE(EnumType) EnumType::enum_type |
| 301 | /** |
| 302 | * Forward declares an scoped enum. |
| 303 | * |
| 304 | * @param NT The scoped enum. |
| 305 | */ |
| 306 | #define NDNBOOST_SCOPED_ENUM_FORWARD_DECLARE(EnumType) struct EnumType |
| 307 | |
| 308 | #else // NDNBOOST_NO_CXX11_SCOPED_ENUMS |
| 309 | |
| 310 | #define NDNBOOST_SCOPED_ENUM_UT_DECLARE_BEGIN(EnumType,UnderlyingType) enum class EnumType:UnderlyingType |
| 311 | #define NDNBOOST_SCOPED_ENUM_DECLARE_BEGIN(EnumType) enum class EnumType |
| 312 | #define NDNBOOST_SCOPED_ENUM_DECLARE_END2() |
| 313 | #define NDNBOOST_SCOPED_ENUM_DECLARE_END(EnumType) ; |
| 314 | |
| 315 | #define NDNBOOST_SCOPED_ENUM_NATIVE(EnumType) EnumType |
| 316 | #define NDNBOOST_SCOPED_ENUM_FORWARD_DECLARE(EnumType) enum class EnumType |
| 317 | |
| 318 | #endif // NDNBOOST_NO_CXX11_SCOPED_ENUMS |
| 319 | |
| 320 | #define NDNBOOST_SCOPED_ENUM_START(name) NDNBOOST_SCOPED_ENUM_DECLARE_BEGIN(name) |
| 321 | #define NDNBOOST_SCOPED_ENUM_END NDNBOOST_SCOPED_ENUM_DECLARE_END2() |
| 322 | #define NDNBOOST_SCOPED_ENUM(name) NDNBOOST_SCOPED_ENUM_NATIVE(name) |
| 323 | |
| 324 | //#ifdef NDNBOOST_NO_CXX11_SCOPED_ENUMS |
| 325 | // |
| 326 | //# define NDNBOOST_SCOPED_ENUM_START(name) struct name { enum enum_type |
| 327 | //# define NDNBOOST_SCOPED_ENUM_END }; |
| 328 | //# define NDNBOOST_SCOPED_ENUM(name) name::enum_type |
| 329 | // |
| 330 | //#else |
| 331 | // |
| 332 | //# define NDNBOOST_SCOPED_ENUM_START(name) enum class name |
| 333 | //# define NDNBOOST_SCOPED_ENUM_END |
| 334 | //# define NDNBOOST_SCOPED_ENUM(name) name |
| 335 | // |
| 336 | //#endif |
| 337 | #endif // NDNBOOST_SCOPED_ENUM_EMULATION_HPP |