Enumerators of scoped enum
s are visible only within the enum
, convert to other types only with a cast, and always support forward-declared because their default underlying type is int
.
Scope
Generally speaking, declaring a name inside curly braces limits the visibility of that name to the scope defined by the braces, with one exception: the C++98-style enum
s, which lead to enumerator names leaking into the scope containing their enum
definition, and thus have an official term - unscoped enum
s.
|
|
As their new C++11 counterparts, by adding a class
in declaration, scoped enum
s don’t leak names:
|
|
Implicit conversion
The fact that scoped enum
s have strong typed enumerators results in their inability to implicitly convert to integral types (and, from there, to floating-point types), which behavior is otherwise permited in terms of unscoped enum
s:
|
|
Instead, in order to convert typefrom Color
to a different type, we need a cast:
|
|
Forward declaration
Technically speaking, both scoped and unscoped enum
s may be forward-declared, except that unscoped ones need a bit of additional work - by specifying the underlying type for unscoped enum
s1:
|
|
Since scoped enum
s have a default underlying type of int
, forward declaration is always supported:
|
|
With the help of forward declaration, the header containing the declarations requires no recompilation if Status
’s definition is revised. Furthermore, it is also possible that continueProcessing
’s implementation need not be recompiled2.
Twist
There’s still some situation where unscoped enum
s may be useful: when referring to fields within C++11’s std::tuple
s. Suppose we have a tuple holding values for the name, email address, and reputation value for a user at a social networking website:
|
|
To get field value, using an unscoped enum
to associate names with field numbers may be helpful:
|
|
To mimic the similar behavior, using scoped enum
s is more verbose:
|
|
To save some typing, we might consider define a helper function, or in a more generalized form, a function template toUType
that takes an arbitrary enumerator and return its value as a compile-time constant:
|
|
In C++14, we may simplify the toUType
to a sleeker form:
|
|
And then we access a field of the tuple like this:
|
|
Still more to write than use of the unscoped enum
, but it also avoids namespace pollution and inadvertent conversions involving enumerators, so those extra characters might still be a reasonable to pay for.
-
Since there is no default underlying type for unscoped
enum
s, to make it possible for compilers to select an underlying type for eachenum
prior to theenum
being used, C++98 supports onlyenum
definitions (when all enumerators are listed), whileenum
declarations are not allowed. ↩︎ -
This happens if
Status
is modified (e.g., add a new enumerator), butcontinueProcessing
’s behavior is unaffected (e.g., the function doesn’t use the newly added enumerator). ↩︎