Navigation



4.5 — Enumerated types

C++ allows programmers to create their own data types. Perhaps the simplest method for doing so is via an enumerated type. An enumerated type is a data type where every possible value is defined as a symbolic constant (called an enumerator). Enumerated types are declared via the enum keyword. Let’s look at an example:

// define a new enum named Color
enum Color
{
    // Here are the enumerators
    // These define all the possible values this type can hold
    COLOR_BLACK,
    COLOR_RED,
    COLOR_BLUE,
    COLOR_GREEN,
    COLOR_WHITE,
    COLOR_CYAN,
    COLOR_YELLOW,
    COLOR_MAGENTA
};

// Declare a variable of enumerated type Color
Color eColor = COLOR_WHITE;

Defining an enumerated type does not allocate any memory. When a variable of the enumerated type is declared (such as eColor in the example above), memory is allocated for that variable at that time.

Enum variables are the same size as an int variable. This is because each enumerator is automatically assigned an integer value based on it’s position in the enumeration list. By default, the first enumerator is assigned the integer value 0, and each subsequent enumerator has a value one greater than the previous enumerator:

enum Color
{
    COLOR_BLACK, // assigned 0
    COLOR_RED, // assigned 1
    COLOR_BLUE, // assigned 2
    COLOR_GREEN, // assigned 3
    COLOR_WHITE, // assigned 4
    COLOR_CYAN, // assigned 5
    COLOR_YELLOW, // assigned 6
    COLOR_MAGENTA // assigned 7
};

Color eColor = COLOR_WHITE;
cout << eColor;

The cout statement above prints the value 4.

It is possible to explicitly define the value of enumerator. These integer values can be positive or negative and can be non-unique. Any non-defined enumerators are given a value one greater than the previous enumerator.

// define a new enum named Animal
enum Animal
{
    ANIMAL_CAT = -3,
    ANIMAL_DOG, // assigned -2
    ANIMAL_PIG, // assigned -1
    ANIMAL_HORSE = 5,
    ANIMAL_GIRAFFE = 5,
    ANIMAL_CHICKEN // assigned 6
};

Because enumerated values evaluate to integers, they can be assigned to integer variables:

int nValue = ANIMAL_PIG;

However, the compiler will not implicitly cast an integer to an enumerated value. The following will produce a compiler error:

Animal eAnimal = 5; // will cause compiler error

It is possible to use a static_cast to force the compiler to put an integer value into an enumerated type, though it’s generally bad style to do so:

Animal eAnimal = static_cast<Animal>(5); // compiler won't complain, but bad style

Each enumerated type is considered a distinct type. Consequently, trying to assign enumerators from one enum type to another enum type will cause a compile error:

Animal eAnimal = COLOR_BLUE; // will cause compile error

Enumerated types are incredibly useful for code documentation and readability purposes when you need to represent a specific number of states.

For example, functions often return integers to the caller to represent error codes when something went wrong inside the function. Typically, small negative numbers are used to represent different possible error codes. For example:

int ParseFile()
{
    if (!OpenFile())
        return -1;
    if (!ReadFile())
        return -2;
    if (!Parsefile())
        return -3;

    return 0; // success
}

However, using magic numbers like this isn’t very descriptive. An alternative method would be through use of an enumerated type:

enum ParseResult
{
    SUCCESS = 0,
    ERROR_OPENING_FILE = -1,
    ERROR_READING_FILE = -2,
    ERROR_PARSING_FILE = -3,
};

ParseResult ParseFile()
{
    if (!OpenFile())
        return ERROR_OPENING_FILE;
    if (!ReadFile())
        return ERROR_READING_FILE;
    if (!Parsefile())
        return ERROR_PARSING_FILE;

    return SUCCESS;
}

This is much easier to read and understand than using magic number return values. Furthermore, the caller can test the function’s return value against the appropriate enumerator, which is easier to understand than testing the return result for a specific integer value.

if (ParseFile() == SUCCESS)
    {
    // do something
    }
else
    {
    // print error message
    }

Another use for enums is as array indices, because enumerator indices are more descriptive than integer indices. We will cover this in more detail in the section on arrays.

Finally, as with constant variables, enumerated types show up in the debugger, making them more useful than #defined values in this regard.

Quiz

1) Define an enumerated type to choose between the following monster types: orcs, goblins, trolls, ogres, and skeletons.

2) Declare a variable of the enumerated type you defined in question 1 and assign it the troll type.

3) True or false. Enumerators can be:
3a) explicitly assigned integer values
3b) not explicitly assigned a value
3c) explicitly assigned floating point values
3d) negative
3e) non-unique
3f) assigned the value of prior enumerators (eg. COLOR_MAGENTA = COLOR_RED)

Quiz answers

1) Show Solution

2) Show Solution

3) Show Solution

4.6 — Typedefs
Index
4.4 — Type conversion and casting

30 comments to 4.5 — Enumerated types

  • [...] own data types that better correspond to the problem being worked upon. You have already seen how enumerated types and structs can be used to create your own custom data [...]

    • christopher11

      This is what i came up with
      #include
      using namespace std;

      enum Race
      {
      RACE_ORC = 1,
      RACE_GOBLIN = 2,
      RACE_TROLL = 3,
      RACE_OGRE = 4
      };

      int pickRace(int race);

      main()
      {
      int x;
      cout<< "Choose your race: " << endl << "Orc(1) – Goblin(2) – Troll(3) – Ogre(4)";
      cout<> x;
      pickRace(x);
      system(“PAUSE”);
      return 0;
      }

      int pickRace(int race)
      {
      static int choice;
      if(race==1)
      {
      choice = RACE_ORC;
      }
      if(race==2)
      {
      choice = RACE_GOBLIN;
      }
      if(race==3)
      {
      choice = RACE_TROLL;
      }
      if(race==4)
      {
      choice = RACE_OGRE;
      }

      if(choice==1)
      {
      cout<<"You picked Orc.";
      }
      if(choice==2)
      {
      cout<<"You picked Goblin.";
      }
      if(choice==3)
      {
      cout<<"You picked Troll.";
      }
      if(choice==4)
      {
      cout<<"You picked Ogre.";
      }
      cout<< endl;
      }

      • PLEASE avoid using system(“PAUSE”). use cin.get() or something but, please avoid using any system(“”) function. That way you’ll be doing favors both for yourself AND others who’re reading your code.

  • tom mason

    When are the enumerators created? Can they be used independently of the enum-type variable? It appears that they are declared as -static const int-

    • Enums are handled at compile time, and they are generally treated as a const int. There is no such thing as a static type, so the static keyword is not applicable. The scope of enum type declarations is the same as normal variables: Enums declared outside of a class or function are treated as global, those inside a block are scoped to that block, and those in a class are considered part of that class.

      For example:

          { // start of a block
              enum Colors
              {
                  COLOR_BLACK,
                  COLOR_WHITE,
                  COLOR_RED
              };
          } // Colors goes out of scope here
      
          Colors cValue; // not valid because Colors is out of scope
      

      Enum values can be used independently of the enum-type variable, as they are essentially treated as integers. For example, the following is valid:

      enum Colors
      {
      COLOR_BLACK,
      COLOR_WHITE,
      COLOR_RED,
      COLOR_GREEN,
      COLOR_BLUE,
      };
      
      int nValue = COLOR_RED;
      

      Note that in the specification for the next version of C++ (C++0x), there will be a new type of enum (called a strongly typed enum) that will be treated as a unique type. These strongly typed enums will not be implicitly convertable to integers.

  • Stuart
    // define a new enum named Animal
    enum Animal
    {
        ANIMAL_CAT = -3;
        ANIMAL_DOG; // assigned -2
        ANIMAL_PIG; // assigned -1
        ANIMAL_HORSE = 5;
        ANIMAL_GIRAFFE = 5;
        ANIMAL_CHICKEN; // assigned 6
    };
    

    Alex, are the semicolons here a mistake?
    My program wouldn’t compile until I changed them to commas:

    #include "stdafx.h"
    #include 
    
    int main()
    {
    	using namespace std;
    
    	// define an enum named Animal - local (inside block)
    	enum Animal
    	{
    		ANIMAL_CAT = -3,
    		ANIMAL_DOG, // assigned to -2
    		ANIMAL_PIG, // assigned to -1
    		ANIMAL_HORSE = 5,
    		ANIMAL_GIRAFFE = 5,
    		ANIMAL_CHICKEN, // assigned to 6
    	};
    	Animal eAnimal = ANIMAL_HORSE;
    	cout << eAnimal << endl;
    	return 0;
    }
    
  • [...] Stuart: That’s strange. The first time I commented (a couple of days ago), it went through okay. Anyway, thanks… [...]

  • Ben

    Not sure I understand its interest. If you’re trying to get a more understandable error message for example, I don’t see much difference as it will still print an integer and not “ERROR_OPENING_FILE”. Same idea with a list of names, etc…
    Is there a way to print the name of the enum and not its integer value?

    Thanks

    • Unfortunately, there’s no easy way to print the name of the enum. The main benefits of using enums are:
      1) Code readability is enhanced, since enums are descriptions and numbers could mean anything
      2) If you ever want to change an enum’s corresponding integer value, you only have to do so in one place, whereas if you use integers everywhere, you might have to change multiple values.

      Enums are often used in conjunction with functions, either as parameters or return values to denote a particular mode or state.

  • Rousseaux

    i will have to reread this lesson later. But i’m with Ben as far as seeing more use in the name of the enum type being printed in the stead of the actual integer. i tried to find a way to cout the name by feeding the integer value but that skill is beyond my scope so far. Once again you’ve fueled new ‘what if’s’ Alex. Well done.

    • If I need the names of a set of enums for something, I’ll usually write a function that takes the enum name to be printed and return a string version of the enum. Something like this:

      std::string GetEnumName(MyEnum eEnum)
      {
          switch (eEnum)
          {
              case ENUM_CASE_1: return "ENUM_CASE_1";
              case ENUM_CASE_2: return "ENUM_CASE_2";
              case ENUM_CASE_3: return "ENUM_CASE_3";
              case ENUM_CASE_4: return "ENUM_CASE_4";
          }
      
          return "";
      }
  • Kinten

    I dont see the reason for usin enums instead of macros, I mean, if you use the enum it is necesary to initiate at least one instance of it, while the macros (#define) replace everyting right away without the memory cost.
    Isn’t this a better solution?

    • Enums and #defines have the same memory requirements. Enum definitions take up no additional memory space because they are just definitions. A good compiler should replace any enum with it’s integer equivalent at compile time, just like #defines are replaced by the preprocessor.

      Enums are always a better choice than #define when you have a set of options to pick from because the syntax checking will exclude you from picking something not part of the enum set. Plus they’re more readable, and debuggers can resolve their values (whereas debuggers generally can not resolve the values of #defines).

  • Sim

    Is there any other situation, in which enumerators are needed typically? Cause as of now I don’t see any difference between doing this:

    enum ParseResult
    {
        SUCCESS = 0,
        ERROR_OPENING_FILE = -1,
        ERROR_READING_FILE = -2,
        ERROR_PARSING_FILE = -3,
    };
    

    and this:

    //parse results
    
    #define SUCCES 0
    #define ERROR_OPENING_FILE -1
    #define ERROR_OPENING_FILE -2
    #define ERROR_OPENING_FILE -3
    

    Obviously these are constants, thus they cannot be changed during runtime. However, if this is the only typical way of using enumerator types, then I don’t see why you wouldn’t just pre-define them using the preprocessor.

  • Shai

    Great work, Alex.
    Your site is better than any C++ book I know of.

  • John
    #include <iostream>
    #include <cstdlib>
    #include <ctime>
    
    using namespace std;
    
    namespace BODY_PARTS
    {
        const int BPMEMBERS = 2;
    
        enum MEMBER_TYPES
        {
            BODY_PART = 0,
            BODY_PART_FLAG = 1,
        };
    
        enum BODY_PARTS
        {
            HEAD = 0,
            TORSO = 1,
            ARM = 2,
            LEG = 3,
        };
    
        enum BODY_PART_STATUS
        {
            FINE = 0,
            SCRATCHED = 1,
            CUT = 2,
            GASHED = 3,
            BROKEN = 4,
            MANGLED = 5,
        };
    }
    using namespace BODY_PARTS;
    
    void PrintBodyPartStatus(int part[BPMEMBERS])
    {
        if (part[BODY_PART] = 0 && part[BODY_PART_FLAG] == 0)
        {
            cout << "Your head is fine";
        }
    
        else cout << part[BODY_PART] << endl << part[BODY_PART_FLAG];
    }
    
    int main()
    {
        int head[BPMEMBERS];
    
        head[BODY_PART] = HEAD;
        head[BODY_PART_FLAG] = FINE;
    
        PrintBodyPartStatus(head);
        return 0;
    }
    

    I hope that is all in code !

    When I run this, I get the exception in the PrintBodyPartStatus(), which prints 0 0.
    And the check above the exception, is expecting a 0, 0.
    What am I missing? Am I doing this wrong? It seems like a viable way to use Enums, as I’ve been using consts for EVERYTHING until I had a look at some open source game Enums.

    I’m currently working on this, so don’t think I’m commenting to expect you to do it for me (which would be nice, I admit)
    But I really didnt’t see the point in typing out

    enum COLOURS
    {
        RED,
        YELLOW,
        GREEN,
        {..}
    };
    

    where in a few less line I coult just type in

    const int RED = 0;
    const int YELLOW = 1;
    const int GREEN = 2;
    {..}
    

    Thanks in advance

    EDIT:
    changing the check from && to || make it work. I’ve always wondered why OR checks work properly and AND checks don’t. (Maybe I’ve been doing those all wrong too, but I’ve always had the problem, even on simple checks.

    even compound if’s don’t work very often

    if(blah)
    {
          if(blah blah)
          {
                 Do(blah blah blah)
          }
    }
    

    Strange.

    • Luiwtf
      if (part[BODY_PART] = 0 && part[BODY_PART_FLAG] == 0)

      should be:

      if (part[BODY_PART] == 0 && part[BODY_PART_FLAG] == 0)

      note the 2 =’s, instead of one :)

      the reason it works with || is because the second half comes up true as you have the == correct, as it is the first part is irrelevant.

      edit – meh, just noticed it’s a month old :D, i suck at remembering dates :p.

  • bla

    I am not really sure about the meaning of questions 3a,b. Does explicit mean explicit cast in this context?

    “3) True or false. Enumerators can be:
    3a) explicitly assigned integer values”
    that would be:

     Animal eAnimal = static_cast<Animal>(5); 

    ??

    3b) not explicitly assigned a value
    ???

    • sm00th_0perat0r
      I'm pretty sure that by explicitly defined, he means setting it equal to a value yourself, as opposed to implicitly</br>defined where the value would be chosen by its order in the list...</br></br>...but I could be wrong!
  • SWEngineer

    Simple well explained tutorial. Thanks.

  • newUser

    If I had not read the comments I would have never noticed enum uses commas! May I suggest having it written in the tutorial too so it draws more attention to it?

  • kalvin

    Enumerations are a little confusing for me. I would better understand them if i had a practical use for them.. I know that no arithmetic operations are allowed on enum, and that since enums are an ordered set of values, you can use relational operators, and loops. this being said I guess I can see how using enum to make your program more readable might be benificial. But to really incorperate enums into your program you will have to input and output enums indirectly as you can not directly output or input enumeration data types.. So for now , i think you have to choose whether to make your program more readable with more work using enumerations, or not and save the extra programming.. Idk maybe as i learn and play with this more i will find its practicality

  • Mindstormscreator

    I’ve seen enums declared without a type before (Animal, Color, etc), are these for defining a bunch of constants essentially?

  • KanedaSyndrome

    This was an area that I haven’t worked with before, so it was fun to get into.

    My contribution:

    prototype:

    enum monsters
    {
    ORC,
    GOBLIN,
    TROLL,
    OGRE,
    SKELETON,
    };

    declaraction and assignment

    monsters newMonster = TROLL;

    test:

    cout << endl << newMonster; //outputs the value 2

    ~KanedaSyndrome

  • Jannat

    Hi. I found these enumerated types really interesting. So I tried to make this program.
    I keep on getting the following error.

    error: no match for ‘operator>>’ in ‘std::cin >> eColour’|

    #include
    using namespace std;
    int main ()
    { //program to input a colour and output the lucky number. lol
    enum colour
    {
    red = 1,
    blue = 2,
    green = 3,
    };
    colour eColour = red;
    cout<<"Choose a colour "<>eColour ;
    cout <<" Your lucky number is "<<eColour<<endl;
    return 0;
    }

    What's wrong with cin ? can these enumerated data types not be input?

  • dice3000

    Awesome tutorial. I actually learned something really useful

  • [...] own data types that better correspond to the problem being worked upon. You have already seen howenumerated types and structs can be used to create your own custom data [...]

You must be logged in to post a comment.