Coming Soon

This lesson is currently being developed

Unscoped enumerations

Create named constants with traditional enums.

Compound Types: Enums and Structs
Chapter
Beginner
Difficulty
40min
Estimated Time

What to Expect

Comprehensive explanations with practical examples

Interactive coding exercises to practice concepts

Knowledge quiz to test your understanding

Step-by-step guidance for beginners

Development Status

In Progress

Content is being carefully crafted to provide the best learning experience

Preview

Early Preview Content

This content is still being developed and may change before publication.

13.2 — Unscoped enumerations

In this lesson, you'll learn about unscoped enumerations (traditional enums) - a way to create named constants that represent a set of related values.

What are unscoped enumerations?

An unscoped enumeration (or just enumeration) is a program-defined type where every possible value is defined as a symbolic constant (called an enumerator). Enumerations are perfect when you need to represent a small set of related options or states.

Think of enumerations like a multiple-choice question where you define all the possible answers ahead of time.

Defining an unscoped enumeration

Here's the basic syntax for defining an enumeration:

enum enumeration_name
{
    enumerator1,
    enumerator2,
    enumerator3,
    // ... more enumerators
};

Let's start with a simple example - representing the colors of a traffic light:

#include <iostream>

enum TrafficLight
{
    red,
    yellow,
    green
};

int main()
{
    TrafficLight currentLight = red;
    
    std::cout << "Current traffic light: " << currentLight << std::endl;
    
    return 0;
}

Output:

Current traffic light: 0

Notice that the output shows 0 instead of red. This is because enumerators are internally represented as integers, starting from 0 by default.

How enumerator values are assigned

By default, enumerators are assigned integer values starting from 0:

#include <iostream>

enum Color
{
    red,    // assigned 0
    green,  // assigned 1  
    blue,   // assigned 2
    yellow  // assigned 3
};

int main()
{
    std::cout << "red = " << red << std::endl;
    std::cout << "green = " << green << std::endl;
    std::cout << "blue = " << blue << std::endl;
    std::cout << "yellow = " << yellow << std::endl;
    
    return 0;
}

Output:

red = 0
green = 1
blue = 2
yellow = 3

Explicit enumerator values

You can explicitly assign specific values to enumerators:

#include <iostream>

enum HttpStatus
{
    ok = 200,
    notFound = 404,
    serverError = 500
};

int main()
{
    HttpStatus response = ok;
    
    std::cout << "HTTP Status: " << response << std::endl;
    
    return 0;
}

Output:

HTTP Status: 200

When you explicitly assign values, subsequent enumerators will continue counting from that point:

#include <iostream>

enum Priority
{
    low = 1,     // explicitly set to 1
    medium,      // automatically assigned 2
    high,        // automatically assigned 3
    critical = 10, // explicitly set to 10
    emergency    // automatically assigned 11
};

int main()
{
    std::cout << "low = " << low << std::endl;
    std::cout << "medium = " << medium << std::endl;
    std::cout << "high = " << high << std::endl;
    std::cout << "critical = " << critical << std::endl;
    std::cout << "emergency = " << emergency << std::endl;
    
    return 0;
}

Output:

low = 1
medium = 2
high = 3
critical = 10
emergency = 11

Using enumerations in practice

Here's a more practical example using enumerations to represent game states:

#include <iostream>

enum GameState
{
    mainMenu,
    playing,
    paused,
    gameOver
};

void handleGameState(GameState state)
{
    if (state == mainMenu)
    {
        std::cout << "Showing main menu" << std::endl;
    }
    else if (state == playing)
    {
        std::cout << "Game is running" << std::endl;
    }
    else if (state == paused)
    {
        std::cout << "Game is paused" << std::endl;
    }
    else if (state == gameOver)
    {
        std::cout << "Game over screen" << std::endl;
    }
}

int main()
{
    GameState currentState = playing;
    
    handleGameState(currentState);
    
    // Change state
    currentState = paused;
    handleGameState(currentState);
    
    return 0;
}

Output:

Game is running
Game is paused

Enumerations with switch statements

Enumerations work particularly well with switch statements:

#include <iostream>

enum Direction
{
    north,
    south,
    east,
    west
};

void move(Direction dir)
{
    switch (dir)
    {
    case north:
        std::cout << "Moving north" << std::endl;
        break;
    case south:
        std::cout << "Moving south" << std::endl;
        break;
    case east:
        std::cout << "Moving east" << std::endl;
        break;
    case west:
        std::cout << "Moving west" << std::endl;
        break;
    }
}

int main()
{
    move(north);
    move(west);
    
    return 0;
}

Output:

Moving north
Moving west

Enumerator scope and naming conflicts

Unscoped enumerations place their enumerators in the same scope as the enumeration itself. This can lead to naming conflicts:

enum Color
{
    red,
    green,
    blue
};

enum TrafficLight
{
    red,    // ERROR: 'red' already defined!
    yellow,
    green   // ERROR: 'green' already defined!
};

To avoid this, use descriptive prefixes or carefully choose your enumerator names:

#include <iostream>

enum Color
{
    color_red,
    color_green,
    color_blue
};

enum TrafficLight  
{
    light_red,
    light_yellow,
    light_green
};

int main()
{
    Color paintColor = color_red;
    TrafficLight signal = light_green;
    
    std::cout << "Paint color: " << paintColor << std::endl;
    std::cout << "Traffic signal: " << signal << std::endl;
    
    return 0;
}

Output:

Paint color: 0
Traffic signal: 2

Comparing enumerations

You can compare enumerators using comparison operators:

#include <iostream>

enum Size
{
    small = 1,
    medium = 5, 
    large = 10
};

int main()
{
    Size shirtSize = medium;
    Size availableSize = large;
    
    if (shirtSize == medium)
    {
        std::cout << "Shirt size is medium" << std::endl;
    }
    
    if (availableSize > shirtSize)
    {
        std::cout << "Available size is larger than needed" << std::endl;
    }
    
    return 0;
}

Output:

Shirt size is medium
Available size is larger than needed

Best practices for enumerations

1. Use descriptive names

// Good
enum PlayerState
{
    idle,
    walking, 
    running,
    jumping
};

// Less clear
enum State
{
    a,
    b,
    c,
    d
};

2. Choose meaningful starting values when appropriate

// Good for months (1-based)
enum Month
{
    january = 1,
    february,
    march,
    // ... etc
};

// Good for priorities (10-based scale)
enum Priority
{
    low = 10,
    medium = 50,
    high = 90
};

3. Consider using enumerations instead of magic numbers

// Before (using magic numbers)
if (playerHealth == 0)
{
    // game over
}

// Better (using enumeration)
enum HealthStatus
{
    dead = 0,
    critical = 25,
    healthy = 100
};

if (playerHealth == dead)
{
    // game over  
}

Common use cases for enumerations

  1. Game states: menu, playing, paused, game over
  2. Directions: north, south, east, west
  3. Days of the week: monday, tuesday, etc.
  4. File operations: read, write, append
  5. Network status: connected, disconnected, connecting
  6. User roles: admin, moderator, user, guest

Key concepts to remember

  1. Enumerators are symbolic constants that represent integer values.

  2. Default numbering starts at 0 and increments by 1.

  3. You can explicitly assign values to enumerators.

  4. Enumerators live in the same scope as the enumeration (unscoped).

  5. Enumerations work well with switch statements and comparison operators.

  6. Be careful of naming conflicts with unscoped enumerations.

Summary

Unscoped enumerations allow you to create named constants that represent a set of related values. They make your code more readable by replacing magic numbers with meaningful names. While they provide better code clarity, you need to be careful about naming conflicts since enumerators are placed in the surrounding scope. In the next lesson, you'll learn how enumerations can be converted to and from integers.

Quiz

  1. What is the default value assigned to the first enumerator in an enumeration?
  2. If you define enum Test { a = 5, b, c };, what are the values of a, b, and c?
  3. Why might unscoped enumerations cause naming conflicts?
  4. What are some good use cases for enumerations?
  5. How do enumerations improve code readability compared to using integer constants?

Practice exercises

Try creating these enumerations:

  1. Create an enumeration for the four seasons and write a program that prints each season's value.
  2. Create an enumeration for difficulty levels (easy=1, medium=5, hard=10) and compare two difficulty values.
  3. Create an enumeration for file permissions (read=4, write=2, execute=1) and use it in a switch statement.
  4. Create an enumeration for card suits and use it to represent a playing card along with a rank.

Continue Learning

Explore other available lessons while this one is being prepared.

View Course

Explore More Courses

Discover other available courses while this lesson is being prepared.

Browse Courses

Lesson Discussion

Share your thoughts and questions

💬

No comments yet. Be the first to share your thoughts!

Sign in to join the discussion