C++11 scoped enumeration

A new type of enumeration known as C++11 scoped enumeration is introduced. This type of enumeration is also known as strong enumeration or classes enumeration because it require mentioning of ‘struct’ or ‘class’ explicitly before the enumeration name.

It has lots of advantages over the C type enumeration. In fact, scoped enumeration was introduced to fill the gap existing in the C type enumeration. In this post we will discuss all the properties exhibited by the scoped enumeration.


Property 1:C++11 Scoped enumeration syntax

While defining scoped enumeration it is required that we mentioned the keyword ‘class‘ or ‘struct‘ to signify that the enumeration is a scoped enum type. If we look at the C type enum, the keyword ‘class’ or ‘struct’ is not required. This is one of the changes made in the scoped enumeration.

enum Value { val 1, val2 } ; //C type enum

enum class New_value { nval1 , nval2 }; //scoped enumeration

enum struct Size { size ,max_size } ; //scoped enumeration

property 2: Using scope resolution operator to access the enumerators

In C type enum, we can directly access the enumerators of the enum by just using their names. But in the scoped enumeration we require the scope resolution(::) operator to use the enumerators.

enum Value{ val }; //unscoped enum

enum class Int { i1 }; //scoped enum

int main( )
{
Value val1=val ; //ok ,unscoped enum

Int i2=i1 ; //error!

Int i2=Int::it ; //work fine, note the scope resolution operator

return 0 ;
}

The scope resolution operator binds the enum name and the enumerator name.



Property 3: Defining the enumerators type explicitly

In the scoped enumeration we can explicitly define the underlying type of the enum class. This means, we can define the type of the enumerators explicitly. To do this we use the colon(:) sign and append the data type to the enum name. Consider the code below.

enum class Int:int { i1, i2 }; 
/** Int is the enum name and i1 , i2 are int type **/

enum class Char:char { c1 ,c2 }; 
/** Char is the enum name and c1 and c2 are char type*/

Defining the enumerators type explicitly doesn’t mean the enumerators can hold the literals of that type. They can hold only constant integer value.

Also note we cannot make the underlying type a floating point type or a string type.

enum class Int:int { i1=90 , i2=78 }; //work fine

enum class Char:char { c1=’C’ , c2=’L’ } ; //ok ,character literal converted to int type

enum class Float_data:float { f1=90.67 } ;//error! underlying type is not const int type

enum class String:string { s1 } ; //error! underlying type cannot be a string type

So how does declaring the underlying type explicitly affect the enum class or the enumerators? When we define the underlying type explicitly we are making the size of the enumerators limit to the size of that type.

By default the enumerators will have the size of int type. But if we define the enumerator’s type as say a char type then the enumerators will have the size of the char type i.e. 1 byte. So defining the type explicitly affect the size of the enumerators.

enum class Int:int { i1 } ;

enum class Long:long long { l1,l2 } ;

enum class Char:char {c1,c2 } ;

cout<< sizeof( Int::i1 ) ; //give 4
cout<< sizeof(Long::l1 ) ; //gives 8
cout << sizeof( Char::c1 ) ; //gives 1

Since the size of enumerators is limited by the type explicitly mentioned, the range of values the enumerators can hold is also limited to the size of that type. For instance, in the enum class having it’s underlying type as char type, the enumerators cannot hold the value 128 or any value greater then 128, because 128 cannot be represented by 7 bits binary digit -the leftmost bit is reserved for the ‘+‘ or ‘‘ sign.

Link :C and C++ Difference between signed and unsigned char type and their uses

enum class Char:char {c1 =128 , //error! too large for char type
c2=127 } ; //work fine

enum class Unsigned_char:unsigned char {c1 =255 , //work fine
c2=256 } ; //error! too large for unsigned char type enumerator

Property 4: enumerators can have the same name

In C type enum we cannot make the name of the enumerators of different enumeration have the same name. But in the scoped enumeration we can.

enum Value { val} ;
enum New { val } ; //error! val already used in Value enum

enum class Size { max_size } ; //work fine 
enum class Int { max_size } ; //work fine

Compiler permits only the enumerators to have the same name, we cannot make the name of the enumeration class similar.

enum class data_size { ds };

enum data_size{ d1 } ;//error! same name as the above enum


Property 5: Cannot implicitly convert to and from int type

The C type enumeration allows implicit conversion of enumerators to int type. This means we can assign enumerators value to int type variable. But in the scoped enumeration implicit conversion to and from int is not allowed. Consider the code below.

enum Value { val} ;

enum class Int:int {i1 , i=89 , i3 } ;

int main( )
{
int i=val ; //work fine, val converted to int type

const int i4=Int::i1 ; //error! i1 cannot be converted to int type

return 0 ;
}

The scoped enumeration is more cautious of how the enumerators are used, and so implicit conversion is not allowed.

Implicit conversion to and from int is not allowed so how do we use the enumerators in our program, the next section explains it.


Property 6:: How to use the enumerators value

Suppose we want to use the enumerators of the scoped enumeration to perform certain operations. Say you want to assign the enumerators value to another int variable. In such case, the only way that will allow us to achieve the task is to cast the enumerators to int type. In ‘property 5’ we have seen that an implicit conversion to and from int is not allowed, so we will perform an explicit casting using static_cast.

enum class Int:int{i1=90, i2=89 };

int val=static_cast<int>(Int::i1) ; //work fine

cout<< val ;

And one other thing that scoped enumeration does not allow is outputting the enumerator’s value to the console screen. In such case also performing static_cast on the enumerator will solve the problem.

enum class Int:int{ i1=90 , i2=89 } ;

cout<< Int::i1 ; //error!!

cout<< static_cast<int>(Int::i1) ; //work fine

Property 7 : Forward declaration with scoped enumeration is allowed

The scoped enumeration allow forward declaration of enum classes. The term ‘forward declaration‘ refer to the declaration of enumeration class without the enumerators.

In C type forward declaration is allowed but we must define the underlying type of the enumeration explicitly. In the scoped enumeration, we need not explicitly define the type to forward declare the enum class because the underlying type will be implicitly declared as int type; the compiler does this for us.

enum Value ; //error!! C type enum and underlying type is missing

enum Value:int ; //work fine, type is mentioned

enum class data_size ; //Still work fine, mentioning of the type not required

Conclusion

The enumeration can be declared as a member of any class. Sometimes when we require a ‘const int’ type member in a class and instead of using the normal ‘const int’ variable we can use the enum. And thus the enumerators will act as the constant data member.