C is not a strong type based language but C++ has been trying to become a stronger type based language. Classes and structures are example of strong types whereas the implicit conversion between different types is an example of weak type system. For example, in the following decelerations implicit conversions are example of weak type systems.

Pointers are another tool to break strong typing. Pr-processor macros also not strong typed. C++11 introduced more type safety in case enumerator type.

Scoped Enums

Let us first look into the loopholes in the traditional C++98 style enumerators-

As per normal rule of declaration when you declare a name inside curly braces the visibility of the name is limited to the scope defined by the curly braces. Like the visibility of a class member is limited within the scope of the class. This means if you want to use the members you have to use the class name(or instance of the class) also. This is not the case for C++98 enumerators. Visibility of enumerator item names are not limited within the enumerator scope but leaks to the scope containing the enumerator. This means if you have an enum like:

Code:

enum ElementaryColor
{
RED,
GREEN,
BLUE
};

you can uses the type like:

auto color = RED;

This also means you cannot use the same names for other variables or functions in the scope containing the enumerator.

Following code snippet of an enumerator definition will give compile errors:

The above enumerators will give compile errors because the names RED, GREEN and BLUE are conflicting. This problem can be more serious if you use two independent 3rd party libraries which define enumerators with conflicting names.

Another issue is the sizes of enumerators. In C++98 style enumerators behave like just constant integer. This is because the underlying type is integer. You cannot not change the underlying type to make it more memory efficient.

Also C++98 enum converts to int implicitly. Following code will compile under C++98 compiler.

If you see the line of code calling the 'ShowColor()' function, compiler has no clue that an invalid value is passed.

So how the C++11/C++14 addresses the issues with enums discussed above?

C++11 introduced a new kind of enumerator type called scoped enum. We will call the traditional enumerators as unscoped enums. Scoped enums are like classes or structures with static values. They are not visible outside the enumerator and need to be qualified with enumerator name. They are declared using 'class' or 'struct' keywords shown later. Their default underlying type is int but can be changed to other integral types to manage the sizes of enums memory efficiently. They cannot be type casted implicitly but explicitly.

C++11 also upgraded the existing unscopped enums to be qualified with enum name(but optional), specifying underlying type other than integer and restriction to implicit type conversion. Below is the syntax of unscoped and scoped enums in C++11:

Where identifier is the enumerator name and type is the underlying integral type.

The major advantage of scoped enum is reduction in namespace pollution. Scoped enum will solve the name conflict problem and allow to have same name in the enum list of two different enums in the same namespace. Following code in C++11 declaring a scoped enum and an unscoped enum with common names:

In C++11 you can control the size of enums by specify underlying type. Default type is int but can be set to char, unsigned long etc. It also introduced new types to be used for enums which are defined in <cstdin> header and the new types are std::int8_t, std::int16_t, std::int32_t, and std::int64_t and unsigned versions of those begin with u like std::uint8_t.

These types are of known sizes across compilers and architectures. For example you can declare an enum like:

Another new feature of scoped enum is forward deceleration. Forward declaration helps to cut down re-compilation time when enum definitions get changed in some scenarios. Consider an example where you have an enum with a big enumerator-list and the list is generated by some third party software and the list is going to be changed very frequently. So in normal scenario your code referring to the enum needs to be compiled whenever the enumerator-list get changed. This is a cumbersome situation and programmers hate this kind of scenario.

C++11 allows you to forward declare an enum with known underlying data type. So if your code is referring to the enum but not referring the enumerator list then your code is not required to re-compile whenever the enum definition (enumerator list) is changed. Forward declaration of enums are shown below:

To get an idea of the usage of forward declaration of enum type let us consider an example where a drawing application code uses a scoped enum for the list of colors it supported. Suppose a header file named colors.h contains the enum definition like:

Now without forward declaration you have to include colors.h wherever you use above functions. In this case every time the enumerator list in the Color enum is changed(which is much more possibility) you need to compile your code. With forward declaration of enum you can avoid this re-compilation. The code will look like:

To compile the above code compiler does not need to know the definition of the enum but size of the enum should be known. Size of the enum depends on the underlying type of the enum. For scoped enum the default underlying type is integer and for unscoped enum it has to be specified explicitly. Above enum could have been declared as

Code:

enum class Color:int;
or
enum Color:int;

I have been doing C++ programming since year 1999 and it was frustrating to use unscoped enumerator type because of the visibility leak. Thanks to modern C++ to add the strong type based enumerator.