From 9092fde17ed8bf30b2564d884a774134b53ae127 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Thu, 5 Jun 2014 00:19:04 +0400 Subject: [PATCH] Added docs for scoped_enum.hpp. Extracted underlying_type to a separate header. --- doc/core.qbk | 7 +- doc/scoped_enum.qbk | 143 +++++++++++++++++++++ include/boost/core/scoped_enum.hpp | 168 ++----------------------- include/boost/core/underlying_type.hpp | 79 ++++++++++++ 4 files changed, 238 insertions(+), 159 deletions(-) create mode 100644 doc/scoped_enum.qbk create mode 100644 include/boost/core/underlying_type.hpp diff --git a/doc/core.qbk b/doc/core.qbk index 64f2ffa..e2fd013 100644 --- a/doc/core.qbk +++ b/doc/core.qbk @@ -23,7 +23,7 @@ criteria for inclusion is that the utility component be: Currently, the Core library contains: -[table +[table [[Component][Utilities]] [ [[link core.addressof addressof]] @@ -68,6 +68,10 @@ Currently, the Core library contains: [ref] [`boost::ref`] ] + [ + [[link core.scoped_enum scoped_enum]] + [Components for portable declaration of scoped enums.] + ] [ [[link core.swap swap]] [`boost::swap`] @@ -85,4 +89,5 @@ Currently, the Core library contains: [include:core no_exceptions_support.qbk] [include:core noncopyable.qbk] [include:core null_deleter.qbk] +[include:core scoped_enum.qbk] [include:core swap.qbk] diff --git a/doc/scoped_enum.qbk b/doc/scoped_enum.qbk new file mode 100644 index 0000000..d0ef888 --- /dev/null +++ b/doc/scoped_enum.qbk @@ -0,0 +1,143 @@ +[section:scoped_enum Headers , ] + +The `boost/core/scoped_enum.hpp` header contains a number of macros that can be used to generate +C++11 scoped enums (7.2 \[dcl.enum\]) if the feature is supported by the compiler, otherwise emulate +it with C++03 constructs. The `BOOST_NO_CXX11_SCOPED_ENUMS` macro from Boost.Config is used to detect +the feature support in the compiler. + +Some of the enumerations defined in the standard library are scoped enums. + + enum class future_errc + { + broken_promise, + future_already_retrieved, + promise_already_satisfied, + no_state + }; + +The user can portably declare such enumeration as follows: + + BOOST_SCOPED_ENUM_DECLARE_BEGIN(future_errc) + { + broken_promise, + future_already_retrieved, + promise_already_satisfied, + no_state + } + BOOST_SCOPED_ENUM_DECLARE_END(future_errc) + +These macros allows to use `future_errc` in almost all the cases as an scoped enum. + + future_errc ev = future_errc::no_state; + +It is possible to specify the underlying type of the enumeration: + + BOOST_SCOPED_ENUM_UT_DECLARE_BEGIN(future_errc, unsigned int) + { + broken_promise, + future_already_retrieved, + promise_already_satisfied, + no_state + } + BOOST_SCOPED_ENUM_DECLARE_END(future_errc) + +The enumeration supports explicit conversion from the underlying type. + +The enumeration can be forward declared: + + BOOST_SCOPED_ENUM_FORWARD_DECLARE(future_errc); + +There are however some limitations: + +* The emulated scoped enum is not a C++ enum, so `is_enum< future_errc >` will be `false_type`. +* The emulated scoped enum can not be used in switch nor in template arguments. For these cases the user needs to use some helpers. + +Instead of + + switch (ev) + { + case future_errc::broken_promise: + // ... + +use + + switch (boost::native_value(ev)) + { + case future_errc::broken_promise: + // ... + +And instead of + + template <> + struct is_error_code_enum< future_errc > : + public true_type + { + }; + +use + + template <> + struct is_error_code_enum< BOOST_SCOPED_ENUM_NATIVE(future_errc) > : + public true_type + { + }; + +* Explicit conversion to the underlying type should be performed with `boost::underlying_cast` instead of `static_cast`: + + unsigned int val = boost::underlying_cast< unsigned int >(ev); + +Sample usage: + + BOOST_SCOPED_ENUM_UT_DECLARE_BEGIN(algae, char) { green, red, cyan }; BOOST_SCOPED_ENUM_DECLARE_END(algae) + ... + algae sample( algae::red ); + void foo( algae color ); + ... + sample = algae::green; + foo( algae::cyan ); + +[heading Deprecated syntax] + +In early versions of the header there were two ways to declare scoped enums, with different pros and cons to each. +The other way used a different set of macros: + + BOOST_SCOPED_ENUM_START(algae) + { + green, + red, + cyan + }; + BOOST_SCOPED_ENUM_END + ... + BOOST_SCOPED_ENUM(algae) sample( algae::red ); + void foo( BOOST_SCOPED_ENUM(algae) color ); + ... + sample = algae::green; + foo( algae::cyan ); + +Here `BOOST_SCOPED_ENUM_START` correcponds to `BOOST_SCOPED_ENUM_DECLARE_BEGIN`, `BOOST_SCOPED_ENUM_END` to `BOOST_SCOPED_ENUM_DECLARE_END` +and `BOOST_SCOPED_ENUM` to `BOOST_SCOPED_ENUM_NATIVE`. Note also the semicolon before `BOOST_SCOPED_ENUM_END`. + +In the current version these macros produce equivalent result to the ones described above and are considered deprecated. + +[heading Acquiring the underlying type of the enum] + +The header `boost/core/underlying_type.hpp` defines the metafunction `boost::underlying_type` which can be used to +obtain the underlying type of the scoped enum. This metafunction has support for emulated scoped enums declared with +macros in `boost/core/scoped_enum.hpp`. When native scoped enums are supported by the compiler, this metafunction +is equivalent to `std::underlying_type`. + +Unfortunately, there are configurations which implement scoped enums but not `std::underlying_type`. In this case +`boost::underlying_type` has to be specialized by user. The macro `BOOST_NO_UNDERLYING_TYPE` is defined to indicate +such cases. + +[heading Acknowledgements] + +Thanks to Andrey Semashev for pointing out that emulation through a namespace +could not be used within classes. + +Helpful comments and suggestions were also made by Kjell Elster, Phil Endecott, +Joel Falcou, Mathias Gaunard, Felipe Magno de Almeida, Matt Calabrese, Vicente +Botet, and Daniel James. + +[endsect] diff --git a/include/boost/core/scoped_enum.hpp b/include/boost/core/scoped_enum.hpp index 4c7b038..2fbdea4 100644 --- a/include/boost/core/scoped_enum.hpp +++ b/include/boost/core/scoped_enum.hpp @@ -7,125 +7,10 @@ // Distributed under the Boost Software License, Version 1.0. // See http://www.boost.org/LICENSE_1_0.txt -/* -[section:scoped_enums Scoped Enums] - -Generates C++0x scoped enums if the feature is present, otherwise emulates C++0x -scoped enums with C++03 namespaces and enums. The Boost.Config BOOST_NO_CXX11_SCOPED_ENUMS -macro is used to detect feature support. - -See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2347.pdf for a -description of the scoped enum feature. Note that the committee changed the name -from strongly typed enum to scoped enum. - -Some of the enumerations defined in the standard library are scoped enums. - - enum class future_errc - { - broken_promise, - future_already_retrieved, - promise_already_satisfied, - no_state - }; - -On compilers that don't support them, the library provides two emulations: - -[heading Strict] - -* Able to specify the underlying type. -* explicit conversion to/from underlying type. -* The wrapper is not a C++03 enum type. - -The user can declare declare these types as - - BOOST_SCOPED_ENUM_DECLARE_BEGIN(future_errc) - { - broken_promise, - future_already_retrieved, - promise_already_satisfied, - no_state - } - BOOST_SCOPED_ENUM_DECLARE_END(future_errc) - -These macros allows to use 'future_errc' in almost all the cases as an scoped enum. - - future_errc err = future_errc::no_state; - -There are however some limitations: - -* The type is not a C++ enum, so 'is_enum' will be false_type. -* The emulated scoped enum can not be used in switch nor in template arguments. For these cases the user needs to use some macros. - -Instead of - - switch (ev) - { - case future_errc::broken_promise: - // ... - -use - - switch (boost::native_value(ev)) - { - case future_errc::broken_promise: - -And instead of - - #ifdef BOOST_NO_CXX11_SCOPED_ENUMS - template <> - struct BOOST_SYMBOL_VISIBLE is_error_code_enum : public true_type { }; - #endif - -use - - #ifdef BOOST_NO_CXX11_SCOPED_ENUMS - template <> - struct BOOST_SYMBOL_VISIBLE is_error_code_enum : public true_type { }; - #endif - - -Sample usage: - - BOOST_SCOPED_ENUM_UT_DECLARE_BEGIN(algae, char) { green, red, cyan }; BOOST_SCOPED_ENUM_DECLARE_END(algae) - ... - algae sample( algae::red ); - void foo( algae color ); - ... - sample = algae::green; - foo( algae::cyan ); - - Light - Caution: only the syntax is emulated; the semantics are not emulated and - the syntax emulation doesn't include being able to specify the underlying - representation type. - - The literal scoped emulation is via struct rather than namespace to allow use within classes. - Thanks to Andrey Semashev for pointing that out. - However the type is an real C++03 enum and so convertible implicitly to an int. - - Sample usage: - - BOOST_SCOPED_ENUM_START(algae) { green, red, cyan }; BOOST_SCOPED_ENUM_END - ... - BOOST_SCOPED_ENUM(algae) sample( algae::red ); - void foo( BOOST_SCOPED_ENUM(algae) color ); - ... - sample = algae::green; - foo( algae::cyan ); - - Helpful comments and suggestions were also made by Kjell Elster, Phil Endecott, - Joel Falcou, Mathias Gaunard, Felipe Magno de Almeida, Matt Calabrese, Vicente - Botet, and Daniel James. - -[endsect] -*/ - - #ifndef BOOST_CORE_SCOPED_ENUM_HPP #define BOOST_CORE_SCOPED_ENUM_HPP #include -#include #ifdef BOOST_HAS_PRAGMA_ONCE #pragma once @@ -135,22 +20,6 @@ namespace boost { #ifdef BOOST_NO_CXX11_SCOPED_ENUMS - /** - * Meta-function to get the underlying type of a scoped enum. - * - * Requires EnumType must be an enum type or the emulation of a scoped enum - */ - template - struct underlying_type - { - /** - * The member typedef type names the underlying type of EnumType. It is EnumType::underlying_type when the EnumType is an emulated scoped enum, - * std::underlying_type::type when the standard library std::underlying_type is provided. - * - * The user will need to specialize it when the compiler supports scoped enums but don't provides std::underlying_type. - */ - typedef typename EnumType::underlying_type type; - }; /** * Meta-function to get the native enum type associated to an enum class or its emulation. @@ -199,12 +68,6 @@ namespace boost #else // BOOST_NO_CXX11_SCOPED_ENUMS - template - struct underlying_type - { - //typedef typename std::underlying_type::type type; - }; - template struct native_type { @@ -222,9 +85,9 @@ namespace boost EnumType native_value(EnumType e) { return e; - } + } -#endif +#endif // BOOST_NO_CXX11_SCOPED_ENUMS } @@ -233,7 +96,7 @@ namespace boost #ifndef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS #define BOOST_SCOPED_ENUM_UT_DECLARE_CONVERSION_OPERATOR \ - explicit operator underlying_type() const { return get_underlying_value_(); } + explicit operator underlying_type() const BOOST_NOEXCEPT { return get_underlying_value_(); } #else @@ -249,10 +112,11 @@ namespace boost */ #define BOOST_SCOPED_ENUM_UT_DECLARE_BEGIN(EnumType, UnderlyingType) \ struct EnumType { \ + typedef void is_boost_scoped_enum_tag; \ typedef UnderlyingType underlying_type; \ EnumType() BOOST_NOEXCEPT {} \ - explicit EnumType(underlying_type v) : v_(v) {} \ - underlying_type get_underlying_value_() const { return v_; } \ + explicit EnumType(underlying_type v) BOOST_NOEXCEPT : v_(v) {} \ + underlying_type get_underlying_value_() const BOOST_NOEXCEPT { return v_; } \ BOOST_SCOPED_ENUM_UT_DECLARE_CONVERSION_OPERATOR \ private: \ underlying_type v_; \ @@ -299,19 +163,19 @@ namespace boost /** * Name of the native enum type. * - * @param NT The new scoped enum. + * @param EnumType The new scoped enum. */ #define BOOST_SCOPED_ENUM_NATIVE(EnumType) EnumType::enum_type /** * Forward declares an scoped enum. * - * @param NT The scoped enum. + * @param EnumType The scoped enum. */ #define BOOST_SCOPED_ENUM_FORWARD_DECLARE(EnumType) struct EnumType #else // BOOST_NO_CXX11_SCOPED_ENUMS -#define BOOST_SCOPED_ENUM_UT_DECLARE_BEGIN(EnumType,UnderlyingType) enum class EnumType:UnderlyingType +#define BOOST_SCOPED_ENUM_UT_DECLARE_BEGIN(EnumType,UnderlyingType) enum class EnumType : UnderlyingType #define BOOST_SCOPED_ENUM_DECLARE_BEGIN(EnumType) enum class EnumType #define BOOST_SCOPED_ENUM_DECLARE_END2() #define BOOST_SCOPED_ENUM_DECLARE_END(EnumType) ; @@ -321,21 +185,9 @@ namespace boost #endif // BOOST_NO_CXX11_SCOPED_ENUMS +// Deprecated macros #define BOOST_SCOPED_ENUM_START(name) BOOST_SCOPED_ENUM_DECLARE_BEGIN(name) #define BOOST_SCOPED_ENUM_END BOOST_SCOPED_ENUM_DECLARE_END2() #define BOOST_SCOPED_ENUM(name) BOOST_SCOPED_ENUM_NATIVE(name) -//#ifdef BOOST_NO_CXX11_SCOPED_ENUMS -// -//# define BOOST_SCOPED_ENUM_START(name) struct name { enum enum_type -//# define BOOST_SCOPED_ENUM_END }; -//# define BOOST_SCOPED_ENUM(name) name::enum_type -// -//#else -// -//# define BOOST_SCOPED_ENUM_START(name) enum class name -//# define BOOST_SCOPED_ENUM_END -//# define BOOST_SCOPED_ENUM(name) name -// -//#endif #endif // BOOST_CORE_SCOPED_ENUM_HPP diff --git a/include/boost/core/underlying_type.hpp b/include/boost/core/underlying_type.hpp new file mode 100644 index 0000000..c79a0a6 --- /dev/null +++ b/include/boost/core/underlying_type.hpp @@ -0,0 +1,79 @@ +// underlying_type.hpp ---------------------------------------------------------// + +// Copyright Beman Dawes, 2009 +// Copyright (C) 2011-2012 Vicente J. Botet Escriba +// Copyright (C) 2012 Anthony Williams +// Copyright (C) 2014 Andrey Semashev + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CORE_UNDERLYING_TYPE_HPP +#define BOOST_CORE_UNDERLYING_TYPE_HPP + +#include + +// GCC 4.7 and later seem to provide std::underlying_type +#if !defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS) || (defined(BOOST_GCC) && BOOST_GCC >= 40700 && defined(__GXX_EXPERIMENTAL_CXX0X__)) +#include +#define BOOST_DETAIL_HAS_STD_UNDERLYING_TYPE +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { + +namespace detail { + +template< typename EnumType, typename Void = void > +struct underlying_type_impl; + +#if defined(BOOST_NO_CXX11_SCOPED_ENUMS) + +// Support for boost/core/scoped_enum.hpp +template< typename EnumType > +struct underlying_type_impl< EnumType, typename EnumType::is_boost_scoped_enum_tag > +{ + /** + * The member typedef type names the underlying type of EnumType. It is EnumType::underlying_type when the EnumType is an emulated scoped enum, + */ + typedef typename EnumType::underlying_type type; +}; + +#endif + +#if defined(BOOST_DETAIL_HAS_STD_UNDERLYING_TYPE) + +template< typename EnumType, typename Void > +struct underlying_type_impl +{ + typedef typename std::underlying_type< EnumType >::type type; +}; + +#endif + +} // namespace detail + +#if !defined(BOOST_NO_CXX11_SCOPED_ENUMS) && !defined(BOOST_DETAIL_HAS_STD_UNDERLYING_TYPE) +#define BOOST_NO_UNDERLYING_TYPE +#endif + +/** + * Meta-function to get the underlying type of a scoped enum. + * + * Requires EnumType must be an enum type or the emulation of a scoped enum. + * If BOOST_NO_UNDERLYING_TYPE is defined, the implementation will not be able + * to deduce the underlying type of enums. The used is expected to specialize + * this trait. + */ +template< typename EnumType > +struct underlying_type : + public detail::underlying_type_impl< EnumType > +{ +}; + +} // namespace boost + +#endif // BOOST_CORE_UNDERLYING_TYPE_HPP