Reputation: 11948
I am a beginner in C++ programming.
Today I come across a new topic: strongly typed enum
. I've researched it a bit but till now I am unable to find out why do we need this and what is the use of the same?
For example if we have:
enum xyz{a, b, c};
/*a = 0, b = 1, c = 2, (Typical C format)*/
Why do we need to write:
enum class xyz{a, b, c};
What are we trying to do here? My most important doubt is how to use it. Could you provide a small example, which will make me understand.
Upvotes: 90
Views: 71183
Reputation: 894
The enum classes ("new enums", "strong enums") address three problems with traditional C++ enumerations:
enums
implicitly convert to int
, causing errors when someone does not want an enumeration to act as an integer.enums
export their enumerators to the surrounding scope, causing name clashes.enum
cannot be specified, causing confusion, compatibility problems, and makes forward declaration impossible. enum class
("strong enums") are strongly typed and scoped:
enum Alert { green, yellow, orange, red }; // traditional enum
enum class Color { red, blue }; // scoped and strongly typed enum
// no export of enumerator names into enclosing scope
// no implicit conversion to int
enum class TrafficLight { red, yellow, green };
Alert a = 7; // error (as ever in C++)
Color c = 7; // error: no int->Color conversion
int a2 = red; // ok: Alert->int conversion
int a3 = Alert::red; // error in C++98; ok in C++11
int a4 = blue; // error: blue not in scope
int a5 = Color::blue; // error: not Color->int conversion
Color a6 = Color::blue; // ok
As shown, traditional enums work as usual, but you can now optionally qualify with the enum's name.
The new enums are "enum class" because they combine aspects of traditional enumerations (names values) with aspects of classes (scoped members and absence of conversions).
Being able to specify the underlying type allow simpler interoperability and guaranteed sizes of enumerations:
enum class Color : char { red, blue }; // compact representation
enum class TrafficLight { red, yellow, green }; // by default, the underlying type is int
enum E { E1 = 1, E2 = 2, Ebig = 0xFFFFFFF0U }; // how big is an E?
// (whatever the old rules say;
// i.e. "implementation defined")
enum EE : unsigned long { EE1 = 1, EE2 = 2, EEbig = 0xFFFFFFF0U }; // now we can be specific
It also enables forward declaration of enums:
enum class Color_code : char; // (forward) declaration
void foobar(Color_code* p); // use of forward declaration
// ...
enum class Color_code : char { red, yellow, green, blue }; // definition
The underlying type must be one of the signed or unsigned integer types; the default is int
.
In the standard library, enum
classes are used for:
<system_error>
: enum class errc
;<memory>
: enum class pointer_safety { relaxed, preferred, strict };
<iosfwd>
: enum class io_errc { stream = 1 };
<future>
: enum class future_errc { broken_promise, future_already_retrieved, promise_already_satisfied };
Several of these have operators, such as ==
defined.
Upvotes: 8
Reputation: 227390
OK, first example: old-style enums do not have their own scope:
enum Animals {Bear, Cat, Chicken};
enum Birds {Eagle, Duck, Chicken}; // error! Chicken has already been declared!
enum class Fruits { Apple, Pear, Orange };
enum class Colours { Blue, White, Orange }; // no problem!
Second, they implicitly convert to integral types, which can lead to strange behaviour:
bool b = Bear && Duck; // what?
Finally, you can specify the underlying integral type of C++11 enums:
enum class Foo : char { A, B, C};
Previously, the underlying type was not specified, which could cause compatibility problems between platforms. Edit It has been pointed out in comments that you can also specify the underlying integral type of an "old style" enum in C++11.
Upvotes: 124
Reputation: 55887
Values of enum class
is really of type enum class
, not underlying_type
as for C-enums.
enum xyz { a, b, c};
enum class xyz_c { d, f, e };
void f(xyz x)
{
}
void f_c(xyz_c x)
{
}
// OK.
f(0);
// OK for C++03 and C++11.
f(a);
// OK with C++11.
f(xyz::a);
// ERROR.
f_c(0);
// OK.
f_c(xyz_c::d);
Upvotes: 11
Reputation: 3133
Enum Scope
Enumerations export their enumerators to the surrounding scope. This has two drawbacks. First, it can lead to name clashes, if two enumerators in different enums declared in the same scope have the same name; second, it's not possible to use an enumerator with a fully qualified name, including the enum name.
enum ESet {a0, a, a1, b1, c3};
enum EAlpha{a, b, c}
select = ESet::a; // error
select = a; // is ambigious
Upvotes: 3
Reputation: 29966
There's a good article about enums at this IBM page, it's very detailed and well-written. Here are some important points in a nutshell:
The scoped enums solve most of the limitations incurred by regular enums: complete type safety, well-defined underlying type, scope issues, and forward declaration.
Upvotes: 19