Mar 29, 2011

Making C++ Enums more like C# Enums

Using C# enums can really spoil a programmer. In case you don't know C#, the enum type is part of the enum. If you have an enum called Handshaking with a member call None, you specify that enum by typing Handshaking.None.  One advantage is if you have another enum member called None they aren't going to collide. The second advantage occurs when you use intellisense (Visual Studio's version of Eclipse's content assist), you only need to remember Handshaking not the names of the enums themselves, they're going to show up automatically when you hit the period.
In C++ I used to use some ugly Hungarian prefixing for my enums. OMG! Why you ask? Well, to get the two advantages mentioned above. Often the enums are public and shared across multiple classes. They all live within the namespace of the project but nonetheless I might have several enums with the option None. If the serial port handshaking enums all start the same then sph_(control-space),  will show me the members. So it works, it's ugly and I've never liked it.


A Better Way

Using C# gave me that aha moment. I can get the same behavior by nesting a namespace. All my code in my project is already under a namespace but I can create a namespace for each and every enum. It's easy, it's clean and I like it.  For instance here's an enum I created for the error types returned when opening or closing a port on the NetBurner platform.


I also include a typedef at the bottom of each enum that combines the namespace and the word Type. I purposefully ignore the actual name for the enum, and then you don't need to ever worry about that name. In fact since each enum is in its own namespace you can call every enum the same, say "Tod" for example, because you want to pay homage to your favorite blogger.  Here's the typedef to show you what I mean.
typedef PortError::Error PortErrorType
If I need to declare a variable of the type for the enum it's just
PortErrorType port_error;
Using a member of the enum becomes
if  (PortError::NeverOpened == port_error) …
The code is self-documenting and easier to read. If you think it's too much to type you're not taking advantage of content assist. If you like ugly non-self-documenting three character prefixes you can always still do something like
namespace SPE = PortError; // or  even (shudder)
using namespace PortError;
I think both are bad ideas, choose good names for your namespaces (don't worry so much about the actual name of the enum, just typedef it into oblivion) and your code will be cleaner.

About Me

My photo
Tod Gentille (@todgentille) is now a Curriculum Director for Pluralsight. He's been programming professionally since well before you were born and was a software consultant for most of his career. He's also a father, husband, drummer, and windsurfer. He wants to be a guitar player but he just hasn't got the chops for it.