DEV Community

loading...
Cover image for Enumerations in C/C++ (traditional enum vs enum class) Part 1

C++ Enum Class Enumerations in C/C++ (traditional enum vs enum class) Part 1

rawrasaurus profile image Rawrasaurus ・3 min read

An enumeration is a user-defined type that consists of a set of named integral constants that are known as enumerators.

In more simple words an enumeration is a way of giving names to a set of constants.

In C++ there are two types of enum:

  1. Traditional enum ("plain enum", "old style enum")
  2. enum classes also commonly referred to as scoped enums

Example declaring a traditional enum:

enum TrafficLight
{
   Green,
   Yellow,
   Red
};
Enter fullscreen mode Exit fullscreen mode

Example declaring a enum class:

enum class StatusNetwork
{
   OK,
   Accepted,
   Created
};
Enter fullscreen mode Exit fullscreen mode

The enum classes ("new enums", "scoped enums", "strong enums") address three problems with traditional C++ enumerations:

  • conventional enums implicitly convert to int, causing errors when someone does not want an enumeration to act as an integer.
  • conventional enums export their enumerators to the surrounding scope, causing name clashes.
  • the underlying type of an enum cannot be specified, causing confusion, compatibility problems, and makes forward declaration impossible.

Now since traditional enums have to export their enumerators to the surrounding scope this can lead to unexpected bugs therefor the names should be unique to avoid compile errors.

Example using traditional enums:

#include <iostream>

using namespace std;

int main()
{
    // Declare a plain enum
    enum TrafficLight
    {
        GREEN,
        YELLOW,
        RED
    };

    TrafficLight trafficlight1 = GREEN;

    // Checking some stuff
    if (trafficlight1 == TrafficLight::GREEN)
        cout << "Traffic light is green!" << endl;
    if (trafficlight1 == TrafficLight::YELLOW)
        cout << "Traffic light is yellow!" << endl;
    if (trafficlight1 == TrafficLight::RED)
        cout << "Traffic light is red!" << endl;

    // Notice the names match the enum TrafficLight this will cause a naming clash
    enum TrainLight
    {
        GREEN,
        YELLOW,
        RED
    };

    TrainLight trainlight1 = GREEN;

    // Checking some stuff
    if (trainlight1 == TrainLight::GREEN)
        cout << "Train light is green!" << endl;
    if (trainlight1 == TrainLight::YELLOW)
        cout << "Train light is yellow!" << endl;
    if (trainlight1 == TrainLight::RED)
        cout << "Train light is red!" << endl;

    return 0;
}

Enter fullscreen mode Exit fullscreen mode

Output:



Compilation failed due to following error(s).

main.cpp: In function int main():
main.cpp:29:9: error: redeclaration of GREEN
         GREEN,
         ^~~~~
main.cpp:11:9: note: previous declaration main()::TrafficLight GREEN
         GREEN,
         ^~~~~
main.cpp:30:9: error: redeclaration of YELLOW
         YELLOW,
         ^~~~~~
main.cpp:12:9: note: previous declaration main()::TrafficLight YELLOW
         YELLOW,
         ^~~~~~
main.cpp:31:9: error: redeclaration of RED
         RED
         ^~~
main.cpp:13:9: note: previous declaration main()::TrafficLight RED
         RED
         ^~~
main.cpp:34:30: error: cannot convert main()::TrafficLight to main()::TrainLight in initialization
     TrainLight trainlight1 = GREEN
                              ^~~~~
Enter fullscreen mode Exit fullscreen mode

alt text

There is a workaround to this if you wish to use traditional enums with multiple matching names, however this is a-bit ugly and takes away from the readability of your program in the long run, nevertheless it compiles.

Example:

#include <iostream>

using namespace std;

int main()
{
    enum TrafficLight
    {
        GREEN,
        YELLOW,
        RED
    };

    TrafficLight trafficlight1 = GREEN;

    // Checking some stuff
    if (trafficlight1 == TrafficLight::GREEN)
        cout << "Traffic light is green!" << endl;
    if (trafficlight1 == TrafficLight::YELLOW)
        cout << "Traffic light is yellow!" << endl;
    if (trafficlight1 == TrafficLight::RED)
        cout << "Traffic light is red!" << endl;

    // Add prefixes to the enum names so that they are unique and no naming clashes
    enum TrainLight
    {
        XGREEN,
        XYELLOW,
        XRED
    };

    TrainLight trainlight1 = XGREEN;

    // Checking some stuff
    if (trainlight1 == TrainLight::XGREEN)
        cout << "Train light is green!" << endl;
    if (trainlight1 == TrainLight::XYELLOW)
        cout << "Train light is yellow!" << endl;
    if (trainlight1 == TrainLight::XRED)
        cout << "Train light is red!" << endl;

    return 0;
}

Enter fullscreen mode Exit fullscreen mode

Output:

Traffic light is green!                                                                                                                                                                       
Train light is green!                                                                                                                                                                                                                                                                                                                                                                

...Program finished with exit code 0                                                                                                                                                          
Press ENTER to exit console.                                                                                                                                                                  
Enter fullscreen mode Exit fullscreen mode

Run the code to preview the results.

The compiler doesn't complain and all seems well in the world.

Thanks for reading! Next time I will explore the much preferred choice of enum classes that cause much less surprises than the traditional enums.

Resources:
Microsoft Docs
Bjarne Stroustrup's C++11 FAQ


Discussion (0)

pic
Editor guide