C++11 Enums

2015-06-27 #c++

Below is a letter I wrote to my C++ classmates at UCSCx.

Hi, everyone,

I want to share a quick note on “enum” which we learned this morning.

Suppose you are writing a game and you have a move() function that can move your hero on screen. It looks something like this:

void move(int dx, int dy) { /*...*/ }

And you want to add a convenient function so that the user of your program can specify the direction and travel distance instead of coordinates. An enum may come in handy! We can use that to specify the directions:

enum direction { N, W, S, E }; //north, west, south, east

And you can write the convenient function like this:

void move(direction d, int distance) {
    switch(d) {
    case N:
        move(0, distance);
        break;
    case W:
        move(-distance, 0);
        break;
    case S:
        move(0, -distance);
        break;
    case E:
        move(distance, 0);
        break;
    }
}

But what if you already had an enum for the difficulty of the game, which is defined as:

enum difficulty { E, N, H }; //easy, normal, hell

And you compile and get:

test_enum.cpp:4:19: error: redefinition of enumerator 'E'
enum difficulty { E, N, H }; //easy, normal, hard
                  ^
test_enum.cpp:4:22: error: redefinition of enumerator 'N'
enum difficulty { E, N, H }; //easy, normal, hard
                     ^ Ouch, compile error! These two enums don't get along with each other since they both defined 'E' and 'N'!

Now what? Of course you can go ahead and change the names of your enumerations, like “NORTH” instead of “N”. But what if you don’t want to use a longer name?

Turns out there are two kinds of enums[1]: scoped and unscoped. The one we used above is called unscoped enumeration. Since it’s unscoped, the names in one enum may collide with those of another. A scoped enum eliminates the collision. For example, we can turn the enum of directions into a scoped one just by adding a class keyword after enum:

enum class direction { N, W, S, E }; //north, west, south, east

And the usage becomes:

void move(direction d, int distance) {
    switch(d) {
    case direction::N:
        move(0, distance);
        break;
    case direction::W:
        move(-distance, 0);
        break;
    case direction::S:
        move(0, -distance);
        break;
    case direction::E:
        move(distance, 0);
        break;
    }
}

(note the added qualifier direction::)

Now both the compiler and your user are happy, and so are you!

Note: Scoped enum is a new thing in C++11 so if you want to use it on Linux or Mac you may need to add a -std=c++0x or -std=c++11 flag to g++ or clang.

[1] http://en.cppreference.com/w/cpp/language/enum

Cheers,

Ken