Click here to Skip to main content
13,202,820 members (54,569 online)
Click here to Skip to main content
Add your own
alternative version

Tagged as


6 bookmarked
Posted 17 Dec 2012

Type Safe Enum in C++

, 19 Mar 2013
Rate this:
Please Sign up or sign in to vote.
This enum class makes it hard to use it wrongly. Enumeration from one type can’t be mixed with any other data type.


As everybody knows, enums in C++ are, at best, not very useful. A lot of solutions have been proposed around the web, all of them with their advantages.   

The solution proposed in this article, mainly focuses on the type safety aspect of the enumeration. It enforces type checking for each enum, avoiding undesired type conversation.  

This enum class makes it hard to use it wrongly. Enumeration from one type can’t be mixed with any other data type.

How it works

Instead of directly exposing a numeric value, this enum model exposes global class instances. Internally, those classes contain the enum numerical value, but it can’t be accessed from the outside. From here, you have a bunch of class instances, each representing a unique enum value. 


The design was the easiest part. The implementation was much harder. How do we implement this kind of
model by using a common and shareable code base? The class heritage was not very helpful here. I tried the template, but it didn't work properly. The only viable solution I ended with was the macro. With a set of generic macros, I was able to generate full classes in a standard way.  

The enum macro must be spread between the header file and the source file. 


Mainly because of the serialization process, we must be able to construct an enum object from a corresponding numerical enum value. And we should also be able to get the numeric ID from an existing enum. To meet those requirements, the enum model provides the FromInt( ) and the ToInt( ) functions. 


This enum model also allows extensible functionality. In the current sample, the ToString( ) function has been added. The bad side of it is, it has to be manually implemented. But it is not mandatory to use the enum. The ToString( ) function can be removed without impact.  

The Problem  

Switch Case… Bad switch case… The switch statement is a real issue for this enum model. Because in C++ only literal values must be supplied inside a switch case statement, I was forced to expose the numerical ID value outside the enum (other than for the serialization). If it wasn't for the switch, I would be able to keep it entirely private. So, to be able to benefit from switch case optimization the numeric enum ID is also public. But, I strongly suggest to not use the ID other than for switch case


It needs a C++ compiler. It runs under MS-VC and the GCC compiler. In its current form, dynamic libraries are not supported. But this should be fixable.

Using the code    

The real macro definition to include in the header file: 

/// Enum macro definition
#define DEFINE_ENUM_BEGIN(classname)  \
    class classname \
    { \
    public: \
       typedef int EValue; \
       static classname FromInt(EValue v)  {return classname(v);} \
       classname(const classname& e) : m_value(e.m_value) { }; \
       inline const classname& operator = (const classname& e) { m_value = e.m_value; return *this; }; \
       inline bool operator == (const classname& e) const  { return (m_value == e.m_value); }; \
       inline bool operator != (const classname& e) const  { return (m_value != e.m_value); }; \
       const char* ToString() const; \
       inline int ToInt() const {return (int)m_value;} \
       inline int operator ()() const {return (int)m_value;} 

#define DEFINE_ENUM_TYPE(classname, type, value) const static int type ## _ID = value; const static classname type;
#define DEFINE_ENUM_END(classname)  \
   private: \
      explicit classname(const EValue v) : m_value(v) { }; \
      EValue m_value; \
#define DEFINE_ENUM_IMPL(classname, type) const classname classname::type((classname::EValue)classname::type ## _ID);

Sample enumeration type declaration and implementation:

/// Data Type declaration (in the header file .h)
DEFINE_ENUM_TYPE(CDataType, Unknown, 0)
DEFINE_ENUM_TYPE(CDataType, Bool,    1)
DEFINE_ENUM_TYPE(CDataType, Int,     2)
DEFINE_ENUM_TYPE(CDataType, Float,   3)

/// Data Type implementation (in the source file .cpp)
DEFINE_ENUM_IMPL(CDataType, Unknown);
const char* CDataType::ToString() const
      case CDataType::Bool_ID :    return "Bool";
      case CDataType::Int_ID :     return "Int";
      case CDataType::Float_ID :   return "Float";
      default: ASSERT(false);      return "Unknown";

Usage example: 

void SetDataType(CDataType ty) 
   m_DataType = ty;

CDataType ty(CDataType::Float);
    case CDataType::Int_ID   : break;
    case CDataType::Float_ID : break;


Somes interesting links that someone provided (sorry, your name was lost when they moved the article):


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Software Developer (Senior)
Canada Canada
I'm the operator with my pocket calculator.

You may also be interested in...


Comments and Discussions

QuestionWhat's the point? Pin
VentsyV19-Mar-13 18:29
memberVentsyV19-Mar-13 18:29 
Suggestionavoiding hand coding toString() Pin
Paul Nader18-Dec-12 2:49
memberPaul Nader18-Dec-12 2:49 
GeneralRe: avoiding hand coding toString() Pin
ajrarn18-Dec-12 8:29
memberajrarn18-Dec-12 8:29 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.171020.1 | Last Updated 19 Mar 2013
Article Copyright 2012 by ajrarn
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid