Search

4.5 — Enumerated types

C++ contains quite a few built in data types. But these types aren’t always sufficient for the kinds of things we want to do. So C++ contains capabilities that allow programmers to create their own data types. These data types are called user-defined data types.

Perhaps the simplest user-defined data type is the enumerated type. An enumerated type (also called an enumeration) is a data type where every possible value is defined as a symbolic constant (called an enumerator). Enumerations are declared via the enum keyword. Let’s look at an example:

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

Note that each enumerator is separated by a comma, and the entire enumeration is ended with a semicolon.

Prior to C++11, a trailing comma after the last enumerator (e.g. after COLOR_MAGENTA) is not allowed (though many compilers accepted it anyway). However, starting with C++11, a trailing comma is allowed. Now that C++11 compilers are more prevalent, use of a trailing comma after the last element is generally considered acceptable.

Naming enums

Enum identifiers are often named starting with a capital letter, and the enumerators are often named using all caps. Because enumerators are placed into the same namespace as the enumeration, an enumerator name can’t be used in multiple enumerations within the same namespace:

Consequently, it’s common to prefix enumerators with a standard prefix like ANIMAL_ or COLOR_, both to prevent naming conflicts and for code documentation purposes.

Enumerator values

Each enumerator is automatically assigned an integer value based on its 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:

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 share the same value as other enumerators. Any non-defined enumerators are given a value one greater than the previous enumerator.

Note in this case, ANIMAL_HORSE and ANIMAL_GIRAFFE have been given the same value. When this happens, the enumerations become non-distinct -- essentially, ANIMAL_HORSE and ANIMAL_GIRAFFE are interchangeable. Although C++ allows it, assigning the same value to two enumerators in the same enumeration should generally be avoided.

Best practice: Don’t assign specific values to your enumerators.
Rule: Don’t assign the same value to two enumerators in the same enumeration unless there’s a very good reason.

Enum type evaluation and input/output

Because enumerated values evaluate to integers, they can be assigned to integer variables. This means they can also be output (as integers), since std::cout knows how to output integers.

This produces the result:

5

The compiler will not implicitly convert an integer to an enumerated value. The following will produce a compiler error:

However, you can force it to do so via a static_cast:

The compiler also will not let you input an enum using std::cin:

One workaround is to read in an integer, and use a static_cast to force the compiler to put an integer value into an enumerated type:

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:

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

Printing enumerators

As you saw above, trying to print an enumerated value using std::cout results in the integer value of the enumerator being printed. So how can you print the enumerator itself as text? One way to do so is to write a function and use an if statement:

Once you’ve learned to use switch statements, you’ll probably want to use those instead of a bunch of if/else statements, as it’s a little more readable.

Enum allocation and forward declaration

Enum types are considered part of the integer family of types, and it’s up to the compiler to determine how much memory to allocate for an enum variable. The C++ standard says the enum size needs to be large enough to represent all of the enumerator values. Most often, it will make enum variables the same size as a standard int.

Because the compiler needs to know how much memory to allocate for an enumeration, you cannot forward declare enum types. However, there is an easy workaround. Because defining an enumeration does not allocate any memory, if an enumeration is needed in multiple files, it is fine to define the enumeration in a header, and #include that header wherever needed.

What are enumerators useful for?

Enumerated types are incredibly useful for code documentation and readability purposes when you need to represent a specific, predefined set 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:

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

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.

Enumerated types are best used when defining a set of related identifiers. For example, let’s say you were writing a game where the player can carry one item, but that item can be several different types. You could do this:

Or alternatively, if you were writing a function to sort a bunch of values:

Many languages use Enumerations to define booleans. A boolean is essentially just an enumeration with 2 enumerators: false and true! However, in C++, true and false are defined as keywords instead of enumerators.

Quiz

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

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

3) True or false. Enumerators can be:
3a) assigned integer values
3b) not 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.5a -- Enum classes
Index
4.4b -- An introduction to std::string

116 comments to 4.5 — Enumerated types

  • Zero Cool

    This is my solution for the Quiz 1 and 2:

    monster.h

    main.cpp

  • Luhan

    I was wondering if is something dangerous trying to make an enum with binary values,
    and use bit flags, or it could cause problems because it isn’t a constant.

  • Sean Yeo

    I wanted to do your sword example, except with the monster names found in the quiz. However, I keep getting the error "control may reach end of non-void function". Since I was essentially using the same code except with monster names, I copy and pasted your code into my IDE:

    I’m using XCode on mac so I’m not sure if that could be the problem

    any help would be appreciated

    thanks!

    • Alex

      I’ve updated the example by providing a default return value in case none of the if statement match. This should address this issue.

  • Taksh

    Hey Alex,

    Can I change the integer value of an enum member after the the enum {}; ends ? (outside of the enum{}; area)

  • Jim Smith

    English is a foreign language for me. Isn’t it more accurate to say:

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

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

    I was thinking… a variable can be of a certain TYPE (bool, int, float or, MonsterRace) and we can assign it a value, not a type (TRUE, 12, 12f or RACE_ORC).

  • AMG

    MonsterType eMonsterType = MONSTER_TROLL;
    eMonsterType = static_cast<Monster> (10); // does not make sense but it works.
    An Int value, which is not part of MonsterType, can be assigned to eMonsterType. Assigning anything to enum type does not make much sense. enum type is a convenient way to label something, and then use enum items to compare with something else.

  • John

    "Each enumerated type is considered a distinct type." How would you define "distinct type"? In the enum Animal example ANIMAL_HORSE and ANIMAL_GIRAFFE share the same value, i.e.

    //www.learncpp.com is on the top of my order of precedence list

    • Alex

      By “enumerated type”, I’m not talking about the enumerators (e.g. ANIMAL_HORSE, ANIMAL_GIRAFFE) , but rather the enumeration itself (Animal). By distinct type, I mean a type that is not recognized as the same as another type (e.g. via typedef or type aliases).

  • felipe

    Prior to C++11, a trailing comma after the last enumerator (e.g. after COLOR_MAGENTA) is not allowed.
    You miss spelled it, good tutorials!

  • Nguyen Long

    Dear Alex, thank you for the tutorial,
    I want to have a question
    Excuse me for reuse your code:

    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
    };

    For this enum, I want to input an integer and output the enum name.
    So you provide me this:

    Color color = static_cast<Color>(5);

    then I do this:

    std::cout << color;

    in order to print out the color name
    I thought that it means with the number 5, it will assign to “color” and print out value “COLOR_CYAN” (the enum place 5)
    But then unfortunately, it printout the value 5 itself.
    So I want to ask:
    What is the function can I use to call the enum value by call it position (like I call number 5 and then it assign my variable to the COLOR_CYAN)?

    Thank you very much for your help!

    • Alex

      If you want to output an enum value as the symbolic name rather than the integer value, you’ll have to write your own function to do it. The function should take a Color and either print a string, or return a string so the caller can send it to std::cout.

  • Nguyen

    Hi Alex,

    You wrote: "Because enumerators are placed into the same namespace as the enumeration, an enumerator name can’t be used in multiple enumerations within the same namespace: "

    I am not quite sure about this.  Here are what I presume "Because enumerators (RED, BLUE, GREEN) are placed into the same namespace as the enumeration (Color) and enumerators (HAPPY, TIRED, BLUE) are placed into the same namespace as the enumeration (Feeling), an enumerator (BLUE) can’t be used in multiple enumerations (Feeling….) within the same namespace (Color & Feeling have the same namespace).  Sounds like I have 3 namespaces???  Two "local" namespaces and one "global"?

    enum Color
    {
    RED,
    BLUE, // BLUE is put into the global namespace
    GREEN
    };

    enum Feeling
    {
    HAPPY,
    TIRED,
    BLUE // error, BLUE was already used in enum Color in the global namespace
    };

    Thanks, Have a great day!

    • Alex

      Because the enumerators for both Color and Feeling are put into the same namespace as Color and Feeling, if Color and Feeling are defined in the same namespace, then the BLUE enumerators will have a naming collision.

      Normal enumerations do not define their own namespace (enum classes do). So Color and Feeling and their enumerators become part of whatever namespace they are defined as part of. This could be the global namespace, or it could be some other namespace.

  • Kanwar Ujjwaldeep Singh

    Hi Alex!
    I am using CODEBLOCKS with Borland Compiler.
    I tried to use the enum type and also struct data type,but none of these working on it.

    eg.
    #include <iostream.h>
    #include<string.h>

    typedef enum Animal
    {
    ANIMAL_CAT = -3,
    ANIMAL_DOG, // assigned -2
    ANIMAL_PIG, // assigned -1
    ANIMAL_HORSE = 5,
    ANIMAL_GIRAFFE = 5, // shares same value as ANIMAL_HORSE
    ANIMAL_CHICKEN // assigned 6
    };

    ERROR:
    main.cpp|13|Error E2146 : Need an identifier to declare|

    eg 2:
    #include <iostream.h>
    #include<string.h>
    enum Color
    {COLOR_BLACK,
    COLOR_RED,
    COLOR_BLUE,
    COLOR_GREEN,
    COLOR_WHITE,
    COLOR_CYAN,
    COLOR_YELLOW,
    COLOR_MAGENTA, // see note about trailing comma on the last enumerator below
    };
    Color paint = COLOR_WHITE;
    Color house(COLOR_BLUE);

    Error;
    Error: Unresolved external ‘_main’ referenced from C:\BORLAND\BCC55\LIB\C0X32.OBJ
    Process terminated with status 2 (0 minute(s), 0 second(s))
    0 error(s), 0 warning(s) (0 minute(s), 0 second(s))

    Please tell,whats wrong?

  • Nguyen

    Hi Alex,

    Sorry for my bad English.  Yes, exactly what I was asking.

    1)Have the user input the integer, and then convert the integer to the corresponding enum.

    std::cout <<"Enter the integer: ";
    int inputColor;
    std::cin >> inputColor;

    Color color = static_cast<Color>(inputColor);
    PrintColor(color);//function call

    2)Have them enter the name as a std::string, then use a conversion function that converts the string (as an input) to an enum (as an output). Make sure you consider case sensitivity!

    std::cout << "Enter the name: ";
    std::string name;
    std::getline(std::cin, name)

    Color color = static_cast<Color>(name);
    PrintColor(color);//function call

    Please let me know if my examples are correct.  If both are correct, I prefer the first one because it is easier for the user to just input the integer without any need to understand how the program works.  In the second example, the user has to look at the enumerator(s) to make sure the user’s input is the same?

    Thanks, Have a great day.

    • Alex

      #1 should work just fine, and is much easier.
      #2 won’t work, because you can’t cast a string to an enum. You’d have to write a function that compared the user’s input string to a string literal and if they matched, returned the enum.

      e.g. if (name==”enum1″) return ENUM1;

      This is more complicated and less performant, so if #1 works for you, you should run with it.

      • Nguyen

        Thank you Alex,

        #2. I think I can come up with a function that compares the user’s input string to a string literal and if they match, return the enum.  

        I’ve just reviewed the lesson to see anywhere I could find why a string can’t be casted to enum, but it is not mentioned.  I assume that Enum types are considered part of the integer family of types and Enumerated values evaluate to integers; therefore, I can’t cast a string to an enumerated type.

        Please let me know if my assumption is correct.

        Thanks, Have a great day

        • Alex

          C++ generally knows how to cast numeric types to other numeric types (where both char and enum are considered numeric types), but it will not convert strings to other types. I presume this was originally done for simplicity and efficiency, since string to numeric conversions (and vice versa) are comparatively expensive.

  • Nguyen

    Hi Alex,

    In the example, looks like I can use std::cin to get input & store it in color.  I’ve learned that the compiler will not let you input an enum using std::cin:.  Could you please write out the statement for this? and the function call for printColor?-  Thank you.

    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
    };

    void printColor(Color color)
    {
        if (color == COLOR_BLACK)
            std::cout << "Black";
        else if (color == COLOR_RED)
            std::cout << "Red";
        else if (color == COLOR_BLUE)
            std::cout << "Blue";
        else if (color == COLOR_GREEN)
            std::cout << "Green";
        else if (color == COLOR_WHITE)
            std::cout << "White";
        else if (color == COLOR_CYAN)
            std::cout << "Cyan";
        else if (color == COLOR_YELLOW)
            std::cout << "Yellow";
        else if (color == COLOR_MAGENTA)
            std::cout << "Magenta";
        else
            std::cout << "Who knows!";
    }

    • Alex

      Sorry, I’m not sure what you’re asking. Are you asking how to have the user input an enum value?

      If so, there are (at least) two ways:
      1) The easiest way is to print a menu of the colors and their corresponding integer values. Have the user input the integer, and then convert the integer to the corresponding enum.
      2) Have them enter the name as a std::string, then use a conversion function that converts the string (as an input) to an enum (as an output). Make sure you consider case sensitivity!

  • kleinstein

    My solution for the MonsterType:

  • Sam

    Hi! Should use

    instead of

    nowadays, to not polute the namespace.

    • Alex

      Hi. That’s a bit of an over-generalization. Enums are still a fine choice if you’re using them inside a namespace or class (in that case, the extra namespacing provided by enum classes probably isn’t needed). If you’re defining them in the global scope, then enum classes are probably better. See the next lesson for more information on enum classes.

      • Sam

        Wow, that’s a fast answer! Thank You for the reply, You’re right, that’s more specific. Didn’t notice the following topic is about exactly that. Shoulda paid attention.

  • Coder

    Hi Alex! Thank you for the tutorial!

    I have a little question concerning quiz 3c:

    In question 3c we were asked, if enumerators can be explicitly assigned floating point values, and answer was false. However, I made a small program where I used static_cast-operator to cast a floating point value to an integer and it worked:

    Did I understood the question incorrectly? Thanks.

  • reznov

    So for the sake of trial I attempted to declare my enum MonsterType in a headerfile and #included the header file in the file I wanted to assign it a value.

    I expected this to work, since the #include statement should’ve been replaced with the content of the header file, but it didn’t. My compiler didn’t seem to know what I was talking about when I called my enum type and it’s values. Is this because it doesn’t allocate memory until assigned? Or is there some other conflict going on here I don’t know about yet?

    • Alex

      No, this should have worked. It’s common to put enums in headers and then #include them. Something else must be going wrong. If you copy the enum from the header into the code file at the point where you did the #include, does it work?

      • reznov

        Yes te enum did work properly when implemented in the code, this is why I started blaming the #include. That was a correct assumption however, as I just reviewed my code after a night of sleep and knowing it should work. My error was using #define ‘monster_type.h’ where the compiler thinks (I don’t know a file called string::monster_type.h), instead of "monster_type.h".

        Eventually was gonna make that mistake one day, might as well be now. Anyway I’m glad the code works, thanks 🙂

  • Sanja

    What do you think under #defined values?

  • Shekhar

    Hi Alex, I am not clear about this statement: "Because the compiler needs to know how much memory to allocate for an enumeration, you cannot forward declare enum types."
    My doubts are:
    1) First of all, is memory allocated at compile time or at run time ?
    2) Second, so when we forward declare a variable, does the compiler set aside memory (or compile the instruction to set aside memory) for it ?
    3) Third, for function forward declarations, does the compiler set aside memory (or compile the instruction to set aside memory) for the function. Since for a function the compiler knows the number of variables from the function forward declaration it’s not a problem. But for an enum forward declaration, it wouldn’t know the number of enumerators within the enum type, is that the reason we cannot forward declare enum types.

    Please let me know your thoughts

    Thanks

    • Alex

      1) Memory is always allocated at run time, but it can be allocated from different regions depending on how the variable is declared.
      2) No, a variable forward declaration just tells the compiler that a variable exists. Only instantiating a variable actually causes memory to be allocated.
      3) Functions are stored in a special region of memory (after all, the code has to live somewhere). Function forward declarations also just tell the compiler that a function exists.

      You’ve hit the nail on the head in point 3 -- the compiler is free to determine how many bytes to allocate to an enum variable -- and to do that, it needs to know how many enumerators are in the enum. It can’t determine that from a forward declaration. The good news is that it hardly matters -- if you put your enumerations in a header file, you can just include that header file wherever you like and have access to the enumerated type. The enumerated type declaration doesn’t take any memory -- only instantiated enum variables do.

  • Darren

    This code will compile without error from c++11 on-wards,

    The enums are said to be strongly typed by following them with the class keyword. However, in order to gain access to the items you have to scope them to their enum names, which makes sense as the items RED and GREEN would be ambiguous otherwise.

  • Jim

    Alex,
    Is the first part of this lesson (shown below) worded incorrectly?  The first sentence alone does not make any sense.  Is enum a data type or just a keyword used to make a new data type of your own? It doesn’t make sense to use a data type to make another data type.  e.g. Enumerator (enum) a data type and COLOR a data type?
    Is COLOR the symbolic constant? What are RED,GREEN,BLUE? So this is confusing.

    It might make sense if type enum was making an array COLOR and all the colors were elements of the array. Can you please clarify this?

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

    • Alex

      I’m not sure where the “Do you need to use” came from. I don’t see that.

      enum is a keyword that allows you to create your own custom enumerated data types.

  • Shiva

    A note on printing enumerators:

    I see a lot of people asking in their comments for a proper way to print enumerator names instead of their integer values. As Alex says there’s no direct way to do this, his own solution being to use a function, which is nice. But I found an easier solution which is to use an array of strings to store the enumerator names, and use the enums as array indices. e.g.

    This is the method I used to print the monster’s type in solving Chapter 4’s Comprehensive Quiz, and it works as expected. No one seems to have mentioned it so far, including Alex, but may be that’s because we haven’t covered arrays yet. It’s pretty obvious to anyone who’s familiar with arrays, just thought I’d share it anyway.

    Is there any downside to the approach? Your thoughts, Alex?

    Keep coding. ~Shiva 🙂

    • Shiva

      EDIT:
          Put a #include <strings> in there before the first line. I missed it. 🙂

    • Alex

      Yes, I didn’t mention this method because we haven’t covered arrays yet. This certainly works. The primary advantage I can think of to this method is that it’s likely to be a little more performant (since an array lookup is probably more performant than a function call). But I’d still recommend using a function for a few reasons:

      * With a function, the mapping between the enumerators and names is made explicit. With an array, you’re implicitly relying on the numeric ordering, which is more prone to error.
      * A switch statement gracefully handles a default case, which you can use for error handling in case you define a new enumerator and forget to assign a string to it. An array doesn’t have a mechanism for catching missing enumerators.
      * C++ won’t give you a warning if you have less array initializers than the size of the array, so it’s easy to accidentally miss an enumerator and have everything off by one.

      • Shiva

        Good points. Another drawback that occurred to me is that this won’t work if the enumerators are explicitly assigned non-continous integer values, because array elements are always referred by continuous indices starting from zero. The syntax is also less readable, especially if one is using enum class instead of normal enums. Still it could be useful for someone who’s actually looking for something like it. 🙂

        So anyone should use this method only in simple, straight-forward cases where performance is a primary factor, a function in all other cases.

        Thanks for the advice, Alex. 🙂

        • Alex

          Good point about non-contiguous enums (though those are uncommon).

          Yes, the key takeaway is using a function is a better practice unless you really need the performance (and it may not even be more performant if your compiler inlines the function). A good rule of thumb is not to optimize too early -- write safe code first, and then if you need more performance, you can figure out how to optimize. Otherwise you’ll likely end up spending time optimizing things that don’t matter, for little benefit.

          • Shiva

            Right on all accounts. Makes sense. Agreed.

            The real gem of this website over other C++ learning resources is very much this platform to ask questions and get the practical methodology and insights of a pro in return. Thanks a lot Alex. 🙂

  • Elpidius

    Hey Alex, could you please clarify (and perhaps reword) this:

    "The C++ standard says the enum size needs to be large enough to represent all of the enumerator values. Most often, it will make enum variables the same size as a standard int."

    So in regards to the enum variable size, are you saying the enum variable needs to be large enough to hold the largest possible integer value of an enumerator?

    For example:

    So in this hypothetical case the largest possible value is 258 (takes up 259 values), which cannot fit inside an 8-bit variable (it can only hold 256 values), hence we need to allocate a 16-bit piece of memory for this enum variable.

    Is my understanding of this correct?

  • Sharaf

    hey i didn’t understand the code

    here why you have used ItemType and itemtype i didn’t understand use of that..
    even how you defined this string i didn’t understand
    std::string(ItemType itemType)

    • Alex

      ItemType is the enumerated type that I’ve defined at the top of the code. itemType (lower case i) is the name of a variable I’m defining. ITEMTYPE_TORCH is the enumerated value that I’m initializing variable itemType with.

      It’s akin to this: int x. int is the type, x is the variable name. In this case, instead of int, we have ItemType. Instead of x, we have itemType.

      I’m not sure what you mean by “std::string(ItemType itemType)”, as that doesn’t occur in the code anywhere.

    • Lyle

      This defines a function named getItemName which returns a string when it returns instead of say, an int which most examples in the tutorial use.

      The argument passed when you call it is one of the Item_Type enum items.
      When the function is called and returns, this example - it will leave a string of "Torch" for cout to display.

  • Jim

    Alex,
    It seems pretty redundant to name an enum Color and then use COLOR_RED as one of the enumerator names. Did you do it that way for a specific reason?

    Why not just use RED like in the first example you showed? Would it be alright to use one or any of these C_RED, COL_RED, CLR_RED instead. I realize you’d have to be consistent with all the enumerators. Differentiating between all of these Color, color, COLOR is real confusing.

    A bit later you used this cast, Color color = static_cast<Color>(inputColor).  However you used color in all lower case letters, how does this one work?

    Can you explain this a little better?

    • Alex

      > It seems pretty redundant to name an enum Color and then use COLOR_RED as one of the enumerator names. Did you do it that way for a specific reason?

      Yes. With normal enums, the enum name isn’t used to scope the enumerator. So let’s say you had two enumerations:

      Color’s BLUE enumerator will have a naming conflict with Mood’s BLUE enumerator. Adding a prefix to the enumerator help avoid naming conflicts and also serves as a reminder of which enumeration the enumerator is from. You can use any prefix you like.

      > Color color = static_cast(inputColor). However you used color in all lower case letters, how does this one work?

      In this line, we’re declaring a variable named color of type Color (no different than how int x declares a variable named x of type int). We’re initializing variable color with the inputColor, converted from an int into a Color.

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter