Coming Soon

This lesson is currently being developed

Unscoped enumerator integral conversions

Understand how enums convert to integers.

Compound Types: Enums and Structs
Chapter
Beginner
Difficulty
35min
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.3 — Unscoped enumerator integral conversions

In this lesson, you'll learn how unscoped enumerations can be converted to and from integers, and the implications of these conversions.

Understanding enumerator values

As you learned in the previous lesson, enumerators are internally represented as integers. This means that enumerations have a close relationship with integral types, and C++ provides ways to convert between them.

Let's start by reviewing how enumerator values work:

#include <iostream>

enum Color
{
    red,      // 0
    green,    // 1
    blue,     // 2
    yellow    // 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

Implicit conversion from enumeration to integer

Unscoped enumerations can be implicitly converted to integers. This means you can use an enumerator anywhere an integer is expected:

#include <iostream>

enum Priority
{
    low = 1,
    medium = 5,
    high = 10
};

int main()
{
    Priority taskPriority = medium;
    
    // Implicit conversion to int
    int priorityValue = taskPriority;  // No explicit cast needed
    
    std::cout << "Task priority as enum: " << taskPriority << std::endl;
    std::cout << "Task priority as int: " << priorityValue << std::endl;
    
    // Can be used in arithmetic operations
    int newPriority = taskPriority + 2;
    std::cout << "New priority: " << newPriority << std::endl;
    
    return 0;
}

Output:

Task priority as enum: 5
Task priority as int: 5
New priority: 7

Using enumerations in arithmetic operations

Since enumerations convert to integers, you can use them in arithmetic operations:

#include <iostream>

enum Level
{
    beginner = 1,
    intermediate = 5,
    advanced = 10
};

int main()
{
    Level currentLevel = intermediate;
    Level targetLevel = advanced;
    
    // Calculate difference
    int levelDifference = targetLevel - currentLevel;
    std::cout << "Levels to advance: " << levelDifference << std::endl;
    
    // Use in comparisons
    if (currentLevel < advanced)
    {
        std::cout << "Still have room to grow!" << std::endl;
    }
    
    // Use in calculations
    int totalExperience = currentLevel * 100;
    std::cout << "Total experience points: " << totalExperience << std::endl;
    
    return 0;
}

Output:

Levels to advance: 5
Still have room to grow!
Total experience points: 500

No implicit conversion from integer to enumeration

While enumerations implicitly convert to integers, the reverse is not true. You cannot implicitly convert an integer to an enumeration:

enum Color
{
    red,
    green,
    blue
};

int main()
{
    Color myColor = red;        // OK: enumerator to enum
    int colorValue = myColor;   // OK: enum to int (implicit)
    
    // myColor = 1;             // ERROR: can't implicitly convert int to enum
    // myColor = colorValue;    // ERROR: can't implicitly convert int to enum
    
    return 0;
}

Explicit conversion from integer to enumeration

If you need to convert an integer to an enumeration, you must use an explicit cast:

#include <iostream>

enum Status
{
    disconnected = 0,
    connecting = 1,
    connected = 2
};

int main()
{
    int statusCode = 2;
    
    // Explicit conversion using static_cast
    Status networkStatus = static_cast<Status>(statusCode);
    
    std::cout << "Status code: " << statusCode << std::endl;
    std::cout << "Network status: " << networkStatus << std::endl;
    
    return 0;
}

Output:

Status code: 2
Network status: 2

Dangers of explicit conversion

When explicitly converting integers to enumerations, you need to be careful that the integer value corresponds to a valid enumerator:

#include <iostream>

enum Grade
{
    F = 0,
    D = 1,
    C = 2,
    B = 3,
    A = 4
};

void printGrade(Grade g)
{
    switch (g)
    {
    case F: std::cout << "Grade: F" << std::endl; break;
    case D: std::cout << "Grade: D" << std::endl; break;
    case C: std::cout << "Grade: C" << std::endl; break;
    case B: std::cout << "Grade: B" << std::endl; break;
    case A: std::cout << "Grade: A" << std::endl; break;
    default: std::cout << "Invalid grade!" << std::endl; break;
    }
}

int main()
{
    // Valid conversions
    Grade grade1 = static_cast<Grade>(2);  // C
    Grade grade2 = static_cast<Grade>(4);  // A
    
    printGrade(grade1);
    printGrade(grade2);
    
    // Dangerous conversion - invalid enumerator value!
    Grade invalidGrade = static_cast<Grade>(99);
    printGrade(invalidGrade);  // Undefined behavior!
    
    return 0;
}

Output:

Grade: C
Grade: A
Invalid grade!

Working with user input

A common use case for integer-to-enumeration conversion is when processing user input:

#include <iostream>

enum MenuChoice
{
    newGame = 1,
    loadGame = 2,
    settings = 3,
    quit = 4
};

void handleChoice(MenuChoice choice)
{
    switch (choice)
    {
    case newGame:
        std::cout << "Starting new game..." << std::endl;
        break;
    case loadGame:
        std::cout << "Loading saved game..." << std::endl;
        break;
    case settings:
        std::cout << "Opening settings..." << std::endl;
        break;
    case quit:
        std::cout << "Goodbye!" << std::endl;
        break;
    }
}

bool isValidChoice(int choice)
{
    return choice >= 1 && choice <= 4;
}

int main()
{
    int userInput;
    
    std::cout << "Main Menu:" << std::endl;
    std::cout << "1. New Game" << std::endl;
    std::cout << "2. Load Game" << std::endl;
    std::cout << "3. Settings" << std::endl;
    std::cout << "4. Quit" << std::endl;
    std::cout << "Enter choice: ";
    
    std::cin >> userInput;
    
    if (isValidChoice(userInput))
    {
        MenuChoice choice = static_cast<MenuChoice>(userInput);
        handleChoice(choice);
    }
    else
    {
        std::cout << "Invalid choice!" << std::endl;
    }
    
    return 0;
}

Example Output (with input "2"):

Main Menu:
1. New Game
2. Load Game
3. Settings
4. Quit
Enter choice: Loading saved game...

Enumerations in function parameters

You can pass enumerations to functions that expect integers:

#include <iostream>

enum ErrorCode
{
    success = 0,
    fileNotFound = 404,
    accessDenied = 403,
    serverError = 500
};

void logError(int code)
{
    std::cout << "Error code: " << code << std::endl;
}

int calculateSeverity(int code)
{
    if (code == 0) return 0;        // No error
    if (code < 500) return 1;       // Client error
    return 2;                       // Server error
}

int main()
{
    ErrorCode error = fileNotFound;
    
    // Can pass enum to function expecting int
    logError(error);  // Implicit conversion
    
    int severity = calculateSeverity(error);
    std::cout << "Error severity level: " << severity << std::endl;
    
    return 0;
}

Output:

Error code: 404
Error severity level: 1

Best practices for enumeration conversions

1. Avoid mixing enumerations and integers in arithmetic

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

int main()
{
    Size shirtSize = medium;
    
    // Questionable: mixing enum with magic number
    int newSize = shirtSize + 3;  // What does +3 mean?
    
    // Better: use meaningful enum values
    if (shirtSize == small)
    {
        shirtSize = medium;  // Explicit upgrade
    }
    
    return 0;
}

2. Validate integer inputs before converting to enum

#include <iostream>

enum Priority
{
    low = 1,
    medium = 2,
    high = 3
};

bool isValidPriority(int value)
{
    return value >= 1 && value <= 3;
}

int main()
{
    int input = 5;  // Invalid priority
    
    if (isValidPriority(input))
    {
        Priority p = static_cast<Priority>(input);
        // Use p safely
    }
    else
    {
        std::cout << "Invalid priority value!" << std::endl;
    }
    
    return 0;
}

Output:

Invalid priority value!

3. Consider using explicit underlying types

You can specify the underlying integer type for an enumeration:

#include <iostream>

enum Status : char  // Explicitly use char as underlying type
{
    inactive = 'I',
    active = 'A',
    pending = 'P'
};

int main()
{
    Status currentStatus = active;
    
    char statusChar = currentStatus;  // Implicit conversion to char
    std::cout << "Status character: " << statusChar << std::endl;
    
    return 0;
}

Output:

Status character: A

Key concepts to remember

  1. Unscoped enumerations implicitly convert to integers - no cast required.

  2. Integers do not implicitly convert to enumerations - explicit cast required.

  3. Use static_cast for integer-to-enumeration conversion and validate the input.

  4. Enumerations can be used in arithmetic operations because they convert to integers.

  5. Always validate integer values before converting to avoid undefined behavior.

  6. You can specify the underlying type of an enumeration explicitly.

Summary

Unscoped enumerations have a close relationship with integers. They can be implicitly converted to integers, allowing them to be used in arithmetic operations and comparisons. However, converting integers back to enumerations requires explicit casting and careful validation to ensure the integer represents a valid enumerator value. Understanding these conversion rules is essential for safe and effective use of enumerations in your programs.

Quiz

  1. Can you implicitly convert an enumeration to an integer? What about the reverse?
  2. What happens if you use static_cast to convert an invalid integer to an enumeration?
  3. Why might you want to validate integer inputs before converting them to enumerations?
  4. How can you specify the underlying type of an enumeration?
  5. What are the potential dangers of using enumerations in arithmetic operations?

Practice exercises

Try these exercises to practice enumeration conversions:

  1. Create an enumeration for months (1-12) and write a function that takes an integer and safely converts it to the month enumeration.
  2. Create an enumeration for HTTP status codes and write a function that categorizes them (1xx info, 2xx success, etc.) using arithmetic operations.
  3. Write a program that reads integers from the user and converts them to a day-of-week enumeration, with proper validation.
  4. Create an enumeration with explicit char values and demonstrate conversion between the enum and character representation.

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