Skip to content

Instantly share code, notes, and snippets.

@TylerBrock
Last active August 29, 2015 14:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save TylerBrock/1201aa0c3f48144d0811 to your computer and use it in GitHub Desktop.
Save TylerBrock/1201aa0c3f48144d0811 to your computer and use it in GitHub Desktop.
Effective Modern C++ Items 10 + 11

Item 10: Prefer scoped enums to unscoped enums

  • Scoped

    • Generally declaring a name inside of curly braces limits scope to inside the braces.

    • Not so for C++98 style enums.

    • Names belong to scope containing the enum

    • Nothing else in that scope can have the same name

      enum Color { black, white, red }; // black, etc in the same scope as color

      auto white = false; // error! white already declared in this scope

    • Because the C++98 style enum names leak into the outer scope we call them unscoped

    • The new C++ style counterpart doesn't leak names in the same way scoped

      enum class Color { black, white, red }; // black, white, red are scoped to color

      auto white = false; // totally ok

      Color c = white; // no enumerator named white in this scope

      Color c = Color::white; // fine

      auto c = Color::white; // better

    • Declared via "enum class" so sometimes referred to as enum classes

  • Strongly Typed

    • Enumerators for unscoped enums implicitly convert to integral types

      enum Color { black, white, red }; // unscoped enum

      std::vectorstd::size_t primeFactors(std::size_t x);

      Color c = red;

      if (c < 14.5) { // compare to double! auto factors = primeFactors(c); // compute primeFactors of a color! }

    • There are no implicit conversions from enumerators in a scoped enum to any other type

    • If you want to perform a conversion from Color to different type use static_cast<type>()

  • Able to be forward declared enum Color; // error

    enum class Color; // works!

    • In C++11 unscoped enums can also be forward declared

    • Compilers choose the underlying type (generally to use the least space, be fast)

    • C++98 only supports enum definitions where all enumerators are listed so that it can select an underlying type.

    • The inability to forward declare enums increases compilation dependencies. Consider a new value being introduced to an enumeration in a header.

      enum Status { good = 0, failed = 1, incomplete = 100, corrupt = 200, indeterminate = 0xFFFFFFFF };

    • In C++11 enums can be forward declared because the underlying type is always known.

      • For the unscoped enums it can be specified.
    • The default underlying type for scoped enums is int.

    • Unscoped enums have no underlying type.

      enum class Status; // underlying type is int enum class Status: std::uint32_t // underlying type is uint32_t (cstdint)

      enum Color: std::uint8_t; // fwd decl for unscoped enum;

      enum class Status: std::uint32_t { good = 0, failed = 1, incomplete = 100, corrupt = 200, autdited = 500, indeterminate = 0xFFFFFFFF };

  • Sometimes the implicit conversion of an unscoped enum to another type (like an integral type can be useful.

    using UserInfo = std::tuple< std::string, // name std::string, // email std::size_t // reputation

    ;

    UserInfo uInfo; auto val = std::get<1>(uInfo);

    enum UserInfoFields { uiName, uiEmail, uiReputation };

    auto val = std::get(uInfo);

    enum class UserInfoFields { uiName, uiEmail, uiReputation };

    auto val = std::get<static_caststd::size_t(UserInfoFields::uiEmail)>(uInfo);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment