Scoped enumerations are defined using enum class as shown below:
enum class Color
{
red,
green,
blue,
};Although we have used class keyword, we are not creating any classes type.
In scoped enumerations, enumerators are not defined in namespace where enumeration is defined, instead they are scoped to the enumeration name itself. To access enumerators, we need to use scope resolution operator with enum name as shown below,
Color value {Color::red};This solves the one problem with unscoped enumerations that it does not pollute the namespace. Additionally, it avoid naming conflicts.
Scoped enumerations are not implicitly converted to integrals
Unlike unscoped enumerations, scope enumerations are not implicitly converted to integrals which solves the following problem:
enum Color
{
red,
green,
blue,
};
enum Feelings
{
happy,
sad,
};
std::cout << (red == happy) << "\n"; // returns trueOperator == leads implicit conversion of red and happy to integral value which is 0 and so the condition yields to true. This is semantically wrong.
If we use scoped enumerations, this would fail.
We still can explicitly do the conversion using static_cast as shown below:
std::cout << static_cast<int>(red) << "\n";A better choice in C++23 would be to use std::to_underlying() defined in header file <utility>. This converts the enumerator to the underlying datatype (base). For example,
std::cout << std::to_underlying(Color::green) << "\n";One more feature that scoped enum provides is that we can directly use list initialization to initialize an integral value without using static_cast, as we do for unscoped enumerations.
Color value{1};