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