Mateusz Loskot :: hacking on, working out, living up

Size of enumeration type in C++

24 May 2009 | mloskot

In C++ enumeration is used to define set of named constants. Each enumeration is a distinct compound type (enumerated type) and is subject to all rules of type system defined in C++ language. Internally, enumeration is represented with so called underlying type. The C++ Standard ISO/IEC 14882:2003 (Section 7.1/5) specifies it as follows:

The underlying type of an enumeration is an integral type that can represent all the enumerator values defined in the enumeration.

It is not specified which particular integral type is used to represent an enumerated type. Given that number of bytes representing fundamental integral types is implementation defined in C++ and only sizeof(char), sizeof(signed char) and sizeof(unsigned char) are guaranteed to be always 1, value reported by sizeof operator applied on enumeration is considered as implementation defined as well. Sometimes one may need to control size of enumerated type in memory, for instance to serialise and de-serialise objects easier.

Some compilers allow to specify underlying type of enumeration. For instance, Microsoft Visual C++ provides dedicated language extension:

<code>enum Color : unsigned char
{
   red, green, blue
};
// assert(sizeof(Color) == 1);
</code>

Obviously, this technique is not portable across other implementations of C++ language.

In order to solve this problem in portable way, a simple class template can be defined:

<code>template <class E, class T>
struct enumeration
{
    typedef T type;
    typedef E enum_type;

    enumeration()
        : e_(E())
    {}

    enumeration(E e)
        : e_(static_cast<T>(e))
    {}

    operator E() const
    { return static_cast<E>(e_); }

private:
    T e_;
};</code>

The enumeration class can be used as a portable way to wrap any enumerated type and to specify (or limit) amount of bytes used to represent it. It is also interchangeable with actual enumeration being wrapped:

<code>#include <cassert>

enum Color { red, green, blue };

int main()
{
    enumeration<Color, unsigned char> color(blue);
    assert(sizeof(color) == 1);

    Color c = color;
    assert(c == blue);
}</code>

It’s also possible to provide default argument for template parameter T specifying underlying type of wrapped enumeration. For instance, if most constant values in a project range from 0 to 255, default type value of T can be unsigned char.

Fork me on GitHub