Skip to content

Enhanced enumerations

Jean-Michel DECORET edited this page Jan 19, 2016 · 2 revisions

Introduction

In Yadoms code, we introduce enhanced enumerations.

The aim of this is to use enumeration either as integer values (common behavior) or as strings.

The use of new enumerations is relatively easy and transparent

How to

Just include an helper file and use included macros.

The helper code should be used as (enhanced) macros. (using boost preprocessor)

There are two steps to use our new enumerations.

  1. declare header in an header file
  2. declare implementation in a cpp file

Declare

Automatic numbering enumeration

In an header file the following macro declare an enumeration named "EEventType" with 5 values. Each enumeration is associated to an integer (like standard c++ enumeration) starting at 0.

   DECLARE_ENUM_HEADER(EEventType,
      ((Unload))
      ((Load))
      ((Crash))
      ((Info))
      ((Error))
   )   

This macros declared the following objects (see 'Switch case' exemple):

Declared Associated integer
EEventType::kUnload 0
EEventType::kLoad 1
EEventType::kCrash 2
EEventType::kInfo 3
EEventType::kError 4

Manually declare each enumeration integer

It is also possible to specify each integer objects (see 'Switch case' exemple):

   DECLARE_ENUM_HEADER(EEventType,
      ((Unload)(-5))
      ((Load)(8))
      ((Crash)(0))
      ((Info)(1))
      ((Error)(1120))
   )   

This macros declared the following objects (see 'Switch case' exemple):

Declared Associated integer
EEventType::kUnload -5
EEventType::kLoad 8
EEventType::kCrash 0
EEventType::kInfo 1
EEventType::kError 1120

Exported enumeration

In fast the enumeration is declared as a class, which can be shared thourgh libraries. In case you want to export the enumeration with keywords like extern "C" or __declspec(dllexport) there is a dedicated macro which allow adding extra qualifiers to the enumeration.

In this case the YADOMS_SHARED_EXPORT is a platform specific export qualifiers.

   DECLARE_ENUM_HEADER_SHARED(EEventType, YADOMS_SHARED_EXPORT,
      ((Unload))
      ((Load))
      ((Crash))
      ((Info))
      ((Error))
   )     

Implementation

The implementation part is needed to declare strings linked to enumeration values.

Automatic generated strings

The simpler way is to let the macro defining the string associated to the value. The generated string is the enumeration case name , lower case.

   DECLARE_ENUM_IMPLEMENTATION(EEventType,
      ((Unload))
      ((Load))
      ((Crash))
      ((Info))
      ((Error))
   )
Declared Associated string
EEventType::kUnload "unload"
EEventType::kLoad "load"
EEventType::kCrash "crash"
EEventType::kInfo "info"
EEventType::kError "error"

In fact, EEventType::kUnload is associated to the string "unload". With any other enumeration EMyEnum::SomeValue_Something, would give "somevalue_something"

Manually declared strings

It is possible to declare the enumeration strings.

   DECLARE_ENUM_IMPLEMENTATION(EEventType,
      ((Unload)("enum0"))
      ((Load)("enum1"))
      ((Crash)("enum2"))
      ((Info)("enum3"))
      ((Error)("enum4"))
   )
Declared Associated string
EEventType::kUnload "enum0"
EEventType::kLoad "enum1"
EEventType::kCrash "enum2"
EEventType::kInfo "enum3"
EEventType::kError "enum4"

Nested enumerations

In case the enumeration is declared as nested, there is a dedicated macros to declare implementation

   DECLARE_ENUM_IMPLEMENTATION_NESTED(CMyClass::EEventType, EEventType,
      ((Unload))
      ((Load))
      ((Crash))
      ((Info))
      ((Error))
   )   

Use of those macros

Declaration

	EEventType 	a; //the first enumeration value is used
	EEventType 	a(0); //use the integer value
	EEventType 	a("load"); //use the string value
	EEventType 	b(a); //use copy constructor
	EEventType 	b(EEventType::kLoad);

Affectation

	EEventType 	a; 
	a = 0;
	a = "load";
	a = EEventType::kLoad;
	EEventType 	b = a; 

Explicit conversion

	EEventType 	a; 
	a.toString();	// return "unload"
	a.toInteger();	// return 0
	EEventType::kLoad.toString(); // return "load"
	EEventType::kLoad.toInteger(); // return 1

Implicit conversion

	void someMethodWithInt(int value) {...}
	void someMethodWithString(std::string value) {...}
	
	EEventType 	a; 
	someMethodWithInt(a);
	someMethodWithInt(EEventType::kLoad);
	someMethodWithString(a);
	someMethodWithString(EEventType::kLoad);

Switch case

This is the only restriction of using the enumeration, declared values cannot be used in case values. For each values, kSomething, there is the constant value kSomethingValue which can be used in case statements.

	int someInt;
	switch(someInt)
	{
		case	EEventType::kLoad :			//do NOT compile
		case	EEventType::kLoadValue :	//compile
		
	}

When Visual Studio will be 100% compliant with C++11, you could update the enumeration macros, so the previous line, which acutally do not compiled, could be used.

Check for definition

According to the C# possibilities, there are methods to check for integer or string definition

	if(EEventType::isDefined(4))
	{
	}
	
	if(EEventType::isDefined("test"))
	{
	}
Clone this wiki locally