C++ Core Guidelines: Rules for Enumerations

The section to enumerations has eight rules. Since C++11, we have scoped enumerations which overcome a lot of the drawbacks of classical enumerations. 

 

hand 162127 640

Enumerations are sets of integer values, which behave like a type. Here is the summary of the rules:

As I mentioned it in the opening to this post: classical enumerations have a lot of drawbacks. Let me explicitly compare classical (unscoped) enumerations and scoped enumerations (sometimes called strongly typed enumerations), because this important comparison is not explicitly described in the rules.

Here is a classical enumeration:

enum Colour{
  red,
  blue,
  green
};

 

Here are the drawbacks of the classical enumerations:

  • The enumerators have no scope
  • The enumerators implicitly convert to implicitly to int
  • The enumerators pollute the global namespace
  • The type of the enumerator is not defined. It just has to be big enough to hold the enumerator.

By using the keyword class or struct, the classical enumeration becomes a scoped enumeration (enum class):

enum class ColourScoped{
  red,
  blue,
  green
};

 

Now, you have to use the scope operator for accessing the enumerators: ColourScoped::red. ColourScoped::red will not implicitly convert to int and will, therefore, not pollute the global namespace. Additionally, the underlying type is per default int. 

After providing the background information we can directly jump into the rules.

Enum.1: Prefer enumerations over macros

Macros don't respect a scope and have no type. This means you can override a previously set macro which specifies a colour.

// webcolors.h 
#define RED   0xFF0000

// productinfo.h
#define RED    0

int webcolor = RED;   // should be 0xFF0000

 

With ColourScoped this will not happen because you have to use the scope operator: ColourScoped webcolour = ColourScoped::red;

This rule is quite obvious because the enumerators are a set of integers which create a kind of a type.  

Enum.3: Prefer enum classes over “plain” enums

The enumerators of a scoped enum (enum class) will not automatically convert to int. You have to access them with the scope operator.

// scopedEnum.cpp

#include <iostream>

enum class ColourScoped{
  red,
  blue,
  green
};

void useMe(ColourScoped color){

  switch(color){
  case ColourScoped::red:
    std::cout << "ColourScoped::red" << std::endl;
    break;
  case ColourScoped::blue:
    std::cout << "ColourScoped::blue" << std::endl;
    break;
  case ColourScoped::green:
    std::cout << "ColourScoped::green" << std::endl;
    break;
  }
}

int main(){

  std::cout <<  static_cast<int>(ColourScoped::red) << std::endl;   // 0
  std::cout <<  static_cast<int>(ColourScoped::red) << std::endl;   // 0

  std::cout << std::endl;

  ColourScoped colour{ColourScoped::red};
  useMe(colour);                                                     // ColourScoped::red

}

 

Enum.4: Define operations on enumerations for safe and simple use

The rules define an enumeration Day which supports the increment operation.

enum Day { mon, tue, wed, thu, fri, sat, sun };

Day& operator++(Day& d)
{
    return d = (d == Day::sun) ? Day::mon : static_cast<Day>(static_cast<int>(d)+1);
}

Day today = Day::sat;
Day tomorrow = ++today;

 

The static_cast is necessary in this example because applying the increment operator inside the increment operator would cause an infinite recursion:

Day& operator++(Day& d)
{
    return d = (d == Day::sun) ? Day::mon : Day{++d};    // error
}

 

Enum.5: Don’t use ALL_CAPS for enumerators

If you use ALL_CAPS for enumerators, you may get a conflict with macros because they are typically written in ALL_CAPS.

#define RED 0xFF0000

enum class ColourScoped{ RED };  // error

Enum.6: Avoid unnamed enumerations

If you can't find a name for the enumerations, the enumerations maybe not related. In this case, you should use a constexpr value.

// bad
enum { red = 0xFF0000, scale = 4, is_signed = 1 };

// good
constexpr int red = 0xFF0000;
constexpr short scale = 4;
constexpr bool is_signed = true;

Enum.7: Specify the underlying type of an enumeration only when necessary

Since C++11, you can specify the underlying type of the enumeration and save memory. Per default the type of a scoped enum is int and, therefore, you can forward declare an enum.

// typeEnum.cpp

#include <iostream>

enum class Colour1{
  red,
  blue,
  green
};
 
enum struct Colour2: char {
  red,
  blue,
  green
};

int main(){

  std::cout << sizeof(Colour1) << std::endl;  // 4
  std::cout << sizeof(Colour2) << std::endl;  // 1

}

Enum.8: Specify enumerator values only when necessary

By specifying the enumerator values it may happen that you set a value twice. The following enumeration Col2 has this issue.

enum class Col1 { red, yellow, blue };
enum class Col2 { red = 1, yellow = 2, blue = 2 };    // typo
enum class Month { jan = 1, feb, mar, apr, may, jun,
                   jul, august, sep, oct, nov, dec }; // starting with 1 is conventional

 

What's next?

I made it relatively short in this post. The meta-rule that you should have to keep in mind is: use scoped enums.

The next section of the C++ core guidelines deals with about 35 rules to resource management. This means we dive in the next post right into the heart of C++.

 

 

 

Thanks a lot to my Patreon Supporters: Matt Braun, Roman Postanciuc, Tobias Zindl, Marko, G Prvulovic, Reinhold Dröge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Animus24, Jozo Leko, John Breland, espkk, Louis St-Amour, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Kris Kafka, Mario Luoni, Neil Wang, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Tobi Heideman, Daniel Hufschläger, Red Trip, Alexander Schwarz, Tornike Porchxidze, Alessandro Pezzato, Evangelos Denaxas, Bob Perry, Satish Vangipuram, Andi Ireland, Richard Ohnemus, Michael Dunsky, Dimitrov Tsvetomir, Leo Goodstadt, Eduardo Velasquez, John Wiederhirn, Yacob Cohen-Arazi, Florian Tischler, and Robin Furness.

 

Thanks in particular to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, and Said Mert Turkal.

 

 

My special thanks to Embarcadero CBUIDER STUDIO FINAL ICONS 1024 Small

 

Seminars

I'm happy to give online seminars or face-to-face seminars worldwide. Please call me if you have any questions.

Bookable (Online)

German

Standard Seminars (English/German)

Here is a compilation of my standard seminars. These seminars are only meant to give you a first orientation.

New

Contact Me

Modernes C++,

RainerGrimmSmall

Tags: enum

Comments   

0 #1 Stanley 2021-02-08 18:14
All of these rules make sense, but how do the core guidelines recommend one keep enums and related strings in sync (think enums and error strings, or enums and description strings). The classical DRY technique was to use X macros. These can be designed to create both the enum or class enum as well as the functions to convert to and from the associated string.

My understanding is that macros are very heavily frowned upon by the C++ core guidelines. What is the recommended alternative?
Quote
0 #2 Lee 2021-07-29 03:35
How about a recommendation on the use of boolean typed enums instead of boolean values as parameters to functions. I hate reading code that has "myFunc(true, false, true, true)". Using enums instead of booleans can make the code much much more readable. Yes, some IDEs can make it easier if you are hovering, but I don't think best practices should necessarily consider the potential IDE being used. The code should be as readable in Visual Studio as it is in Vim. And yes, people could just create a named variable and assign it a value and then pass it but that is just tedious and clutters my code. Thoughts?
Quote

My Newest E-Books

Course: Modern C++ Concurrency in Practice

Course: C++ Standard Library including C++14 & C++17

Course: Embedded Programming with Modern C++

Course: Generic Programming (Templates)

Course: C++ Fundamentals for Professionals

Interactive Course: The All-in-One Guide to C++20

Subscribe to the newsletter (+ pdf bundle)

Blog archive

Source Code

Visitors

Today 413

Yesterday 5761

Week 413

Month 125819

All 7188109

Currently are 178 guests and no members online

Kubik-Rubik Joomla! Extensions

Latest comments