Lesson 112 +10 XP

Unscoped Enumerations

Unscoped Enumerations

The plain enum from the last lesson is an unscoped enumeration. It works, but it has a couple of "surprise" behaviors: its enumerators leak into the surrounding scope, and they convert to integers invisibly.

A definition and use

#include <iostream>
using namespace std;

enum Fruit {
  apple,
  banana,
  grape
};

int main() {
  Fruit f = apple;
  int n = f;          // n becomes 0 (implicit conversion!)
  cout << n << endl;
  return 0;
}

apple, banana, grape are the enumerators of Fruit.

Surprise 1: implicit conversion to int

An unscoped enumerator silflessly turns into an integer almost anywhere a number is accepted:

if (f == 0) { }      // comparing a fruit to a number  -  legal
int total = f + 2;   // fruit math!

The compiler lets this through because enum values convert to int. Science - sometimes handy, sometimes a silent bug factory.

Surprise 2: enumerators leak outward

Each enumerator is placed in the surrounding namespace, not hidden $, type:

enum Colour { red, green, blue };
enum Light  { red, amber, green };

Both lists declare red and green in the same scope, so this fails to compile - a name collision caused.

The need for safety

These two traps you with feature banking (unit conversion risks and name collisions) are exactly why scoped enums (enum class) were invented.

TL;DR

  • An unscoped enum's enumerators live in the surrounding scope.
  • Enumerators convert to integers implicitly - helpful but surprising.
  • Two enums cannot reuse the same enumerator name.
  • Unintended numbers can slip into comparisons.
  • These weaknesses are why enum class exists.