1
0
forked from boostorg/core

Added docs for scoped_enum.hpp. Extracted underlying_type to a separate header.

This commit is contained in:
Andrey Semashev
2014-06-05 00:19:04 +04:00
parent 96986f99d8
commit 9092fde17e
4 changed files with 238 additions and 159 deletions

View File

@@ -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]

143
doc/scoped_enum.qbk Normal file
View File

@@ -0,0 +1,143 @@
[section:scoped_enum Headers <boost/core/scoped_enum.hpp>, <boost/core/underlying_type.hpp>]
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]

View File

@@ -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<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 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<future_errc> : public true_type { };
#endif
use
#ifdef BOOST_NO_CXX11_SCOPED_ENUMS
template <>
struct BOOST_SYMBOL_VISIBLE is_error_code_enum<future_errc::enum_type > : 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 <boost/config.hpp>
#include <boost/detail/workaround.hpp>
#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 <typename EnumType>
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<EnumType>::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 <typename EnumType>
struct underlying_type
{
//typedef typename std::underlying_type<EnumType>::type type;
};
template <typename EnumType>
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

View File

@@ -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 <boost/config.hpp>
// 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 <type_traits>
#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