RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Safeguard Your enums: Make Them Strongly-Typed-2 : Page 2

Implicit Conversions
Contemporary enum types (henceforth, I will refer to them as traditional enum types) are only partially type-safe. Indeed, it's impossible to initialize an enum variable with an enumerator of a different enum type:

enum Set {E1=1, E2};
enum Dir{Up, Down};
Set s=E1; //OK, same type
s=2;//error, can't convert int to Set
s=Down; //error, can't convert Dir to Set
However, implicit conversions of enum types to integral types are allowed. They can cause unpredictable runtime behavior, as the following example shows:

bool b=s; //dangerous, s's value is unknown
b=E2; //undefined behavior
Some compilers will issue warning messages when they encounter such mishaps. However, it isn't always possible to tell at compile time whether the value of enum variable can fit into a Boolean value. If s equals E1, the initialization of b is valid. If however s equals E2, b will have an indeterminate value.

Size Issues
The inability to specify a predictable and portable size for enum types is another problem, particularly in applications that serialize data or read data from remote databases. Consider the enumeration Set. A C++ compiler is free to store it in a char, or use a larger underlying type for it such as short, int, and long. This means that the sizeof (s) can range between one to four bytes, depending on the specific compiler and compilation flags used. Presently, standard C++ has no mechanism for specifying an underlying type of enum types. If you must have a specific underlying type, the current workaround consists of replacing enum types with plain constants:

const int32 E1=1;
const int32 E2=2;
However, this approach is inelegant and dangerous. The programmer must provide an explicit value for each constant, risking the creation of duplicates:

//..long list of constants 
const int32 E73=1; //oops, same as E1
Traditional enums have one more problem. The scope of their enumerators propagates to their enclosing scope, often causing name conflicts and ambiguity:

enum Dir {Up, Down}; //Up & Down are globally visible
enum Rate {Up, Down};//error, Up & Down already defined
int main()
 int Rate=5;//error, Height already defined
Although Dir and Rate are distinct types, their enumerators are globally visible, causing name conflicts. In contemporary C++, there are two common workarounds to this problem:
  • declaring the enumerators in different namespaces
  • changing the enumerators' names
The first technique is cumbersome and can still cause name conflicts if a source file has multiple using declarations. The latter is slightly better, but it isn't always an option for programmers using third-party libraries and compiled binaries. It's time to see how the new strongly-typed enums solve all these problems elegantly.

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date