| Home | Libraries | People | FAQ | More

## scoped_enum

### Authors

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

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

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

### 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.

### 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.

### Acknowledgments

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.