How to emulate C++11’s ‘enum class’ in C++03

One of many neat features in C++11 is the introduction of ‘enum class’ – this addresses problems arising from enum declarations such as scoping (the enum cases leak in the same scope as the enum type) and implicit conversion to integer. See Stroustrup’s C++11 FAQ for more details.

However, in the papers that motivated the new language feature (N1513 and N2347) they discuss the current workarounds for C++03. One such workaround is to define a class to represent the enum type – it’s much more verbose than the new C++11 feature, but it solves the scoping and conversion issues.

// Header file
class Weekday
  // Note that the private enum cases have underscores to differentiate
  // from the public cases
  typedef enum Weekday_ { Mon_, Tues_, Wed_, Thurs_, Fri_, Sat_, Sun_ };
  Weekday_ value_;

  static const Weekday Mon, Tues, Wed, Thurs, Fri, Sat, Sun;
  explicit Weekday( const Weekday_& value ) : value_( value ){}

  bool operator<( const Weekday& rhs ) const { return this->value_ < rhs.value_; }
  bool operator==( const Weekday& rhs ) const { return this->value_ == rhs.value_; }
  bool operator!=( const Weekday& rhs ) const { return !(this->operator==(rhs)); }

// Source file
// Definitions for the public Weekday instances 
// in terms of the private enum
const Weekday Weekday::Mon( Mon_ );
const Weekday Weekday::Tues( Tues_ );
const Weekday Weekday::Wed( Wed_ );
const Weekday Weekday::Thurs( Thurs_ );
const Weekday Weekday::Fri( Fri_ );
const Weekday Weekday::Sat( Sat_ );
const Weekday Weekday::Sun( Sun_ );

That’s it – I’ve been using this recently and it works pretty well. I also added a “to_int()” member and a static “from_int()” member to explicitly convert bewteen the enum class and integers – the implementation is simply a switch over the enum cases.


Filed under C++, C++ Code, Programming

8 responses to “How to emulate C++11’s ‘enum class’ in C++03

  1. M

    Why not simply keep the `enum` public (would be far less boilerplate)?

    • If the enum is public then its cases are all in global scope. That means you can have clashes between the cases in different enums. See the examples in Stroustrup’s FAQ as per the link in my post – both enum Alert and enum TrafficLight have cases red and yellow. The purpose of the enum class workaround is to avoid ambiguity in the presence of such name clashes.

      • M

        Hi! I don’t think they’re going to be in a global scope if it’s a public _member_.

        For instance, consider `struct ScopeName { enum { A, B, C }; };`. There is no way for `A`, `B`, or `C` to ever leak outside of `ScopeName` — i.e., you always have to access these as fully-qualified, e.g., `ScopeName::A`.

        Now, if you need multiple `ScopeName`s, simply define multiple structs, each nesting one (and only one) `enum` individually.

        Wouldn’t that be simpler — and just as safe & robust?

      • Hi – yes, I agree your example is a simpler way to address the scoping issue. It doesn’t address the issue of implicit conversion to int though (which was another motivating factor behind the enum class feature in C++11).

      • M

        Here’s an example of what I mean using the types from Stroustrup’s FAQ:

        struct Alert { enum { green, yellow, orange, red }; };

        struct Color { enum Color { red, blue }; };

        Note that there’s no ambiguity — `Alert::red` is distinct from `Color::red`.

      • M

        Typo, the second one should’ve been: `struct Color { enum { red, blue }; };`

      • M

        Thanks for the reply!

        Yeah, I think I agree, it’s scoped, but it is also implicitly convertible.

        At the risk of veering deep(er) into the off-topic / more niche area (sorry! :]) I may add that this occasionally comes in handy.

        Say, suppose you have an `std::array` (fixed-size) with indexes that have meaningful (and invariant) interpretation.

        It’s often convenient to use the names (and avoid magic numbers) for these; e.g., `std::array colors; colors[Color::Red] = 255;` (and so on).

        This avoids using magic numbers (does `1` stand for `Red` or `Green`? who knows! :]) — while keeping contiguity and alignment (and, thus, vectorization) guarantees not offered by, say, a `struct` (or an equivalent wrapper like `std::tuple`).

        I think that having to explicitly convert here would be a bit too much in terms of the required boilerplate, though; wouldn’t it?

        What do you think?

  2. M

    // There’s been a formatting issue with my last comment (angle brackets removed, probably treated as HTML): `std::array` should have `3` elements.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.