C++ Exploring The Darker Corners

 TIP 1:
 Why you should use scoped enumerations

Replacing unscoped enumerations, i.e. enum, with the scoped enumerations introduced by C++11, i.e. enum class might seem like a no-brainer, however, there are good reasons why it's useful to understand where scoped enumerations provide real benefits.

Consider the following example taken over from a drawing program. Assume we would like to represent the following types of brush patterns and the following styles of lines. As you can see, both Brush Pattern and Pen Style have a type Solid.

Unscoped enumerations export their enumerators into the surrounding scope. As a result, if we choose to represent the problem with unscoped enumerations, i.e. without the keyword class, we are going to get a name clash resulting in a compiler error: "Solid" conflicts with a previous declaration.

// Unscoped enum won't compile - name clash because of Solid
enum BrushPattern {Solid, Horizontal, Vertical, Cross};
enum PenStyle {Solid, Dash, Dot, DashDot};

In C++03, we could have provided scope for the enumerations by placing them into dedicated classes, i.e. Pen, Brush. See below. However, this approach is not always practical/applicable, as we might not have access to Brush / Pen API. Additionally, in some cases, we might be interested in making the enumerations available to a larger number of classes.

// C++03 Providing scope for enumerations by placing them into a class
class Brush {
    public:
        enum BrushPattern {Solid, Horizontal, Vertical, Cross};
};

class Pen {
    public:
        enum PenStyle {Solid, Dash, Dot, DashDot};
};

void f(Pen::PenStyle p){
    if(p == Pen::Solid){
    }
}

The second approach which we could have applied in C++03, involves a name change. For example, we could have replaced the value Solid by SolidLine. This is inelegant and rather tedious. Judge for yourself:

// Unscoped enum - changing the name, compiles, but tedious
enum BrushPattern {SolidPattern, HorizontalPattern, VerticalPattern, CrossPattern};
enum PenStyle {SolidLine, DashLine, DotLine, DashDotLine};

Fortunately, this is where scoped enumerations of C++11, i.e. enum class come to the rescue. By placing the keyword class after the specifier enum we get the desired effect without any workarounds.

// C++11 Scoped enum - compiles
enum class BrushPattern {Solid, Horizontal, Vertical, Cross};
enum class PenStyle {Solid, Dash, Dot, DashDot};

In addition to name clash prevention, another important property of scoped enumerations is that their values are strongly typed, thus they aren't implicitly convertible to integers or any other type. This prevents from erroneous uses such as the one below. The first function takes two integers, the second one takes an integer and an enumeration. Unfortunately, the functions have similar names and the developer passed the enumeration to the wrong function. Adding the keyword class would have prevented this mistake since such code simply wouldn't compile!

void f1(int a, int b){
    std::cout << a << ' ' << b;
}

void f2(FileType f, int b){
    std::cout << f << ' ' << b;
}

int main() {
    // the developer intended to call f2 but called f1 instead
    // unfortunately, with unscoped enums this compiles fine
    f1(Pdf, 2);
}