Learning C++11 (Part 3)

Scoped Enums

C++11 introduces scoped enums which reduces namespace pollution and provides values that are more strongly typed. Consider the following contrived case.

Old C++

  enum NetworkSpeed
  {
    kSlow,
    kFast,
    kLudicrous
  };

  enum AirplaneSpeed
  {
    kSlow,
    kFast,
    kLudicrous
  };

That won't compile because AirplaneSpeed redefines all the enum values. Instead we'd have to do something like this:

Old C++

  enum NetworkSpeed
  {
    kNetworkSpeedSlow,
    kNetworkSpeedFast,
    kNetworkSpeedLudicrous
  };

  enum AirplaneSpeed
  {
    kAirplaneSpeedSlow,
    kAirplaneSpeedFast,
    kAirplaneSpeedLudicrous
  };

C++11

  enum class NetworkSpeed
  {
    kSlow,
    kFast,
    kLudicrous
  };

  enum class AirplaneSpeed
  {
    kSlow,
    kFast,
    kLudicrous
  };

Now in order reference each value you have to do something like NetworkSpeed::kSlow or AirplaneSpeed::kFast. This can be especially important if those enums aren't even defined in the same file.

Along with better naming you get strong typing. Before an enum can be implicitly cast to an int, but with scoped enums if you want a different type you will have to do an explicit cast. The verboseness is a small price to pay for type safety.

  NetworkSpeed net_speed = NetworkSpeed::kSlow;
  int temp = static_cast<int>(net_speed);

Note that the default underlying type for scoped enums is int, while unscoped enums do not have a default. Both support specifiying the underlying type.

  enum Fish;              // unscoped - no default type
  enum Cat: int;          // unscoped - explicitly an int
  enum class Dog;         // scoped - defaults to int
  enum class Snake: char; // scoped - explicitly a char

This leads to forward declaration. It requires that the enum has an underlying type. Obviously then, scoped enums can always be forward declared, but unscoped enums must have their underlying type specified.

-- Garner Halloran (Engine Programmer)