[/
 / Copyright (c) 2009 Beman Dawes
 / 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 accompanying
 / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 /]

[section:scoped_enum scoped_enum]

[simplesect Authors]

* Beman Dawes
* Vicente J. Botet Escriba
* Anthony Williams

[endsimplesect]

[section Overview]

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 allow using `future_errc` in almost all the cases as a 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);

In C++03, scoped enums behave differently in case of calling an overloaded function when one overload takes a scoped enum as a parameter, and the other takes a parameter of an integral type. Consider the following code:

    enum enum_regular { REGULAR_A, REGULAR_B };

    BOOST_SCOPED_ENUM_DECLARE_BEGIN(enum_scoped)
    {
        a, b
    }
    BOOST_SCOPED_ENUM_DECLARE_END(enum_scoped)

    void regular_or_int(enum_regular); // (1)
    void regular_or_int(int);          // (2)
    void scoped_or_int(enum_scoped);   // (3)
    void scoped_or_int(int);           // (4)

    regular_or_int(REGULAR_A);                  // calls (1) in C++03 and C++11
    scoped_or_int(enum_scoped::a);              // calls (3) in C++11 but (4) in C++03!
    scoped_or_int(enum_scoped(enum_scoped::a)); // calls (3) in C++03 and C++11

Here is usage example:

    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 );

[endsect]

[section 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` corresponds 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.

[endsect]

[section 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.

[endsect]

[section Acknowledgements]

This scoped enum emulation was developed by Beman Dawes, Vicente J. Botet Escriba and Anthony Williams.

Helpful comments and suggestions were also made by Kjell Elster, Phil Endecott, Joel Falcou, Mathias Gaunard, Felipe Magno de Almeida,
Matt Calabrese, Daniel James and Andrey Semashev.

[endsect]

[endsect]
