All Courses
Working With Data

Enums, Structs, and Unions in C++


Enumerations (Enums)

Enums create named integer constants for better code readability.

Traditional Enums (C-style)

// Basic enum declaration
enum Color {
    RED,        // 0
    GREEN,      // 1
    BLUE        // 2
};

// With explicit values
enum Status {
    PENDING = 1,
    APPROVED = 2,
    REJECTED = 3,
    CANCELLED = 100
};

// Usage
Color c = RED;
Status s = APPROVED;

⚠️ Problems with Traditional Enums

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    TRADITIONAL ENUM PROBLEMS                                 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                              β”‚
β”‚  1. NO SCOPE - Values pollute enclosing namespace                           β”‚
β”‚     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚     β”‚  enum Color { RED, GREEN, BLUE };                                β”‚    β”‚
β”‚     β”‚  enum TrafficLight { RED, YELLOW, GREEN }; // ❌ ERROR!         β”‚    β”‚
β”‚     β”‚                      ^^^          ^^^^^                          β”‚    β”‚
β”‚     β”‚                      Redefinition of RED and GREEN!              β”‚    β”‚
β”‚     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚                                                                              β”‚
β”‚  2. IMPLICIT CONVERSION - Converts to int silently                          β”‚
β”‚     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚     β”‚  Color c = RED;                                                  β”‚    β”‚
β”‚     β”‚  int x = c;        // Compiles! x = 0                           β”‚    β”‚
β”‚     β”‚  c = 42;           // May compile on some compilers!            β”‚    β”‚
β”‚     β”‚  if (c == 5) {...} // Compiles! Meaningless comparison          β”‚    β”‚
β”‚     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚                                                                              β”‚
β”‚  3. NO TYPE SAFETY - Different enums can be compared                        β”‚
β”‚     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚     β”‚  enum Fruit { APPLE, ORANGE };                                   β”‚    β”‚
β”‚     β”‚  enum Planet { MARS, VENUS };                                    β”‚    β”‚
β”‚     β”‚  if (APPLE == MARS) {...}  // Compiles! Both are 0              β”‚    β”‚
β”‚     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚                                                                              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Enum Class (C++11) - The Solution βœ…

// Scoped enum (strongly typed)
enum class Color {
    Red,
    Green,
    Blue
};

enum class TrafficLight {
    Red,        // No conflict with Color::Red
    Yellow,
    Green       // No conflict with Color::Green
};

// Must use scope operator
Color c = Color::Red;
TrafficLight t = TrafficLight::Red;

// No implicit conversion
// int x = c;           // ❌ ERROR!
int x = static_cast<int>(c);  // βœ“ Explicit cast required

// Type-safe comparisons
// if (c == t) {...}    // ❌ ERROR! Different types
if (c == Color::Red) {...}  // βœ“ OK

Enum Class Features

// Specify underlying type
enum class ErrorCode : uint32_t {
    None = 0,
    NotFound = 404,
    ServerError = 500,
    MaxValue = 0xFFFFFFFF
};

enum class SmallEnum : uint8_t {
    A, B, C, D  // Uses only 1 byte
};

// Forward declaration (requires underlying type)
enum class Status : int;

void processStatus(Status s);  // Can use before full definition

enum class Status : int {
    Active,
    Inactive,
    Pending
};

Enum Class Visualization

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                      ENUM vs ENUM CLASS                                      β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                              β”‚
β”‚  Traditional Enum:                  Enum Class:                              β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”           β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                  β”‚
β”‚  β”‚ enum Color {        β”‚           β”‚ enum class Color {  β”‚                  β”‚
β”‚  β”‚   RED,              β”‚           β”‚   Red,              β”‚                  β”‚
β”‚  β”‚   GREEN,            β”‚           β”‚   Green,            β”‚                  β”‚
β”‚  β”‚   BLUE              β”‚           β”‚   Blue              β”‚                  β”‚
β”‚  β”‚ };                  β”‚           β”‚ };                  β”‚                  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜           β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                  β”‚
β”‚           β”‚                                 β”‚                                β”‚
β”‚           β–Ό                                 β–Ό                                β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”           β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                  β”‚
β”‚  β”‚  Global Namespace   β”‚           β”‚    Color Scope      β”‚                  β”‚
β”‚  β”‚  RED = 0            β”‚           β”‚  Color::Red = 0     β”‚                  β”‚
β”‚  β”‚  GREEN = 1          β”‚           β”‚  Color::Green = 1   β”‚                  β”‚
β”‚  β”‚  BLUE = 2           β”‚           β”‚  Color::Blue = 2    β”‚                  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜           β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                  β”‚
β”‚                                                                              β”‚
β”‚  Access: RED                       Access: Color::Red                        β”‚
β”‚  Type:   int (implicit)            Type:   Color (strict)                   β”‚
β”‚  Safe:   No                        Safe:   Yes                              β”‚
β”‚                                                                              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Structures (Structs)

Structs group related data together. In C++, structs are almost identical to classes (default public access).

Basic Struct

// Define a struct
struct Point {
    double x;
    double y;
};

// Create and initialize
Point p1;           // Members uninitialized
Point p2 = {3.0, 4.0};  // Aggregate initialization
Point p3{1.0, 2.0};     // C++11 uniform initialization
Point p4 = {.x = 5.0, .y = 6.0};  // C++20 designated initializers

// Access members
p1.x = 10.0;
p1.y = 20.0;
double distance = sqrt(p1.x * p1.x + p1.y * p1.y);

Struct with Methods

struct Rectangle {
    double width;
    double height;

    // Member functions
    double area() const {
        return width * height;
    }

    double perimeter() const {
        return 2 * (width + height);
    }

    void scale(double factor) {
        width *= factor;
        height *= factor;
    }

    // Static member
    static Rectangle square(double side) {
        return {side, side};
    }
};

// Usage
Rectangle rect{10.0, 5.0};
cout << "Area: " << rect.area() << endl;
rect.scale(2.0);

Rectangle sq = Rectangle::square(5.0);

Struct vs Class

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                         STRUCT vs CLASS                                      β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                              β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”            β”‚
β”‚  β”‚        struct             β”‚    β”‚         class             β”‚            β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€    β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€            β”‚
β”‚  β”‚ Default access: PUBLIC    β”‚    β”‚ Default access: PRIVATE   β”‚            β”‚
β”‚  β”‚ Default inheritance:      β”‚    β”‚ Default inheritance:      β”‚            β”‚
β”‚  β”‚   PUBLIC                  β”‚    β”‚   PRIVATE                 β”‚            β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜            β”‚
β”‚                                                                              β”‚
β”‚  Convention:                                                                 β”‚
β”‚  β€’ struct - Simple data containers (POD), no invariants                     β”‚
β”‚  β€’ class  - Complex types with behavior, encapsulation, invariants          β”‚
β”‚                                                                              β”‚
β”‚  Examples:                                                                   β”‚
β”‚  struct Point { int x, y; };           // Simple data                       β”‚
β”‚  struct Color { uint8_t r, g, b, a; }; // Simple data                       β”‚
β”‚  class BankAccount { ... };            // Has invariants (balance >= 0)     β”‚
β”‚  class DatabaseConnection { ... };      // Complex behavior                 β”‚
β”‚                                                                              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Nested Structs

struct Address {
    string street;
    string city;
    string country;
    int zipCode;
};

struct Person {
    string name;
    int age;
    Address address;  // Nested struct

    void print() const {
        cout << name << ", " << age << " years old\n";
        cout << "Address: " << address.street << ", "
             << address.city << ", " << address.country << endl;
    }
};

// Usage
Person p = {
    "John Doe",
    30,
    {"123 Main St", "New York", "USA", 10001}
};
p.print();

POD (Plain Old Data) Structs

// POD struct - can be used with C, memcpy, etc.
struct PodStruct {
    int id;
    double value;
    char name[50];
    // No virtual functions, no constructors, no private/protected
};

// Check if POD (C++11)
static_assert(std::is_pod<PodStruct>::value, "PodStruct must be POD");

// Modern check (C++17+)
static_assert(std::is_trivially_copyable_v<PodStruct>);
static_assert(std::is_standard_layout_v<PodStruct>);

Unions

Unions allow storing different types in the same memory location. Only one member can be active at a time.

Basic Union

union Value {
    int i;
    float f;
    char c;
};

// All members share the same memory
Value v;
cout << sizeof(v) << endl;  // Size of largest member (int or float = 4)

v.i = 42;        // Store int
cout << v.i;     // OK: 42

v.f = 3.14f;     // Now store float (overwrites int!)
cout << v.f;     // OK: 3.14
// cout << v.i;  // Undefined behavior! (reading inactive member)

Union Memory Layout

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        UNION MEMORY LAYOUT                                   β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                              β”‚
β”‚  union Value {                                                               β”‚
β”‚      int i;      // 4 bytes                                                  β”‚
β”‚      float f;    // 4 bytes                                                  β”‚
β”‚      char c;     // 1 byte                                                   β”‚
β”‚  };                                                                          β”‚
β”‚                                                                              β”‚
β”‚  Memory (4 bytes, overlapping):                                              β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                  β”‚
β”‚  β”‚ Byte 0  β”‚ Byte 1  β”‚ Byte 2  β”‚ Byte 3  β”‚                                  β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€                                  β”‚
β”‚  β”‚              int i                     β”‚  ← Uses all 4 bytes             β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€                                  β”‚
β”‚  β”‚             float f                    β”‚  ← Uses all 4 bytes             β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€                                  β”‚
β”‚  β”‚ char c  β”‚       (unused)              β”‚  ← Uses only 1 byte              β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                  β”‚
β”‚                                                                              β”‚
β”‚  v.i = 42;     [00101010][00000000][00000000][00000000]                     β”‚
β”‚  v.f = 3.14f;  [11000011][11110101][01001000][01000000]                     β”‚
β”‚  v.c = 'A';    [01000001][????????][????????][????????]                     β”‚
β”‚                                                                              β”‚
β”‚  All members START at the SAME address!                                      β”‚
β”‚                                                                              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Tagged Union Pattern

// Safe usage with a type tag
enum class ValueType { Int, Float, String };

struct TaggedValue {
    ValueType type;
    union {
        int i;
        float f;
        // string s;  // ❌ Can't have non-trivial types in union
    };

    void setInt(int val) {
        type = ValueType::Int;
        i = val;
    }

    void setFloat(float val) {
        type = ValueType::Float;
        f = val;
    }

    void print() const {
        switch (type) {
            case ValueType::Int:   cout << "Int: " << i << endl; break;
            case ValueType::Float: cout << "Float: " << f << endl; break;
            default: cout << "Unknown type" << endl;
        }
    }
};

std::variant (C++17) - Type-Safe Union

#include <variant>
#include <string>

// Type-safe alternative to union
std::variant<int, float, std::string> value;

value = 42;           // Store int
value = 3.14f;        // Store float
value = "hello";      // Store string

// Access with std::get
try {
    int i = std::get<int>(value);  // Throws if wrong type
} catch (std::bad_variant_access& e) {
    cout << "Wrong type!" << endl;
}

// Safe access with std::get_if
if (auto* p = std::get_if<std::string>(&value)) {
    cout << "String: " << *p << endl;
}

// Pattern matching with std::visit
std::visit([](auto&& arg) {
    using T = std::decay_t<decltype(arg)>;
    if constexpr (std::is_same_v<T, int>) {
        cout << "int: " << arg << endl;
    } else if constexpr (std::is_same_v<T, float>) {
        cout << "float: " << arg << endl;
    } else if constexpr (std::is_same_v<T, std::string>) {
        cout << "string: " << arg << endl;
    }
}, value);

Bit Fields

Pack multiple values into a single integer for memory efficiency.

Basic Bit Fields

struct StatusFlags {
    unsigned int isActive : 1;    // 1 bit
    unsigned int priority : 3;    // 3 bits (0-7)
    unsigned int errorCode : 4;   // 4 bits (0-15)
    unsigned int reserved : 24;   // 24 bits
};  // Total: 32 bits = 4 bytes

StatusFlags flags;
flags.isActive = 1;
flags.priority = 5;
flags.errorCode = 12;

// Single integer operations
struct Packed {
    uint8_t a : 4;  // 4 bits (0-15)
    uint8_t b : 4;  // 4 bits (0-15)
};  // Total: 1 byte

Bit Field Layout

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        BIT FIELD LAYOUT                                      β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                              β”‚
β”‚  struct StatusFlags {                                                        β”‚
β”‚      unsigned int isActive : 1;    // 1 bit                                 β”‚
β”‚      unsigned int priority : 3;    // 3 bits                                β”‚
β”‚      unsigned int errorCode : 4;   // 4 bits                                β”‚
β”‚      unsigned int reserved : 24;   // 24 bits                               β”‚
β”‚  };                                                                          β”‚
β”‚                                                                              β”‚
β”‚  32-bit integer layout:                                                      β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚
β”‚  β”‚  reserved (24 bits)              β”‚errβ”‚ pri β”‚aβ”‚                      β”‚     β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚
β”‚  │←──────── 24 bits ────────────────→│←4→│←3─→│1β”‚                           β”‚
β”‚  bit 31                                                              bit 0   β”‚
β”‚                                                                              β”‚
β”‚  Example: isActive=1, priority=5, errorCode=12                              β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚
β”‚  β”‚  00000000 00000000 00000000       β”‚1100β”‚ 101 β”‚1β”‚                    β”‚     β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚
β”‚                                       β”‚     β”‚    └─ isActive = 1            β”‚
β”‚                                       β”‚     └───── priority = 5 (101)       β”‚
β”‚                                       └───────── errorCode = 12 (1100)      β”‚
β”‚                                                                              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Practical Bit Field Example

// Network packet header
struct IPv4Header {
    uint8_t version : 4;      // IP version
    uint8_t headerLength : 4; // Header length
    uint8_t tos;              // Type of service
    uint16_t totalLength;     // Total length
    uint16_t id;              // Identification
    uint16_t flags : 3;       // Flags
    uint16_t fragOffset : 13; // Fragment offset
    uint8_t ttl;              // Time to live
    uint8_t protocol;         // Protocol
    uint16_t checksum;        // Header checksum
    uint32_t srcAddr;         // Source address
    uint32_t destAddr;        // Destination address
};

// Color with alpha (RGBA)
struct Color32 {
    uint8_t r : 8;  // Red
    uint8_t g : 8;  // Green
    uint8_t b : 8;  // Blue
    uint8_t a : 8;  // Alpha
};  // Exactly 32 bits = 4 bytes

Recommended Conventions

βœ… Do

// 1. Use enum class instead of plain enum
enum class Direction { North, South, East, West };

// 2. Specify underlying type when needed
enum class ErrorCode : uint16_t { OK = 0, Error = 1 };

// 3. Use structs for simple data aggregates
struct Point { double x, y; };

// 4. Use std::variant instead of union (C++17+)
std::variant<int, double, string> value;

// 5. Initialize all struct members
Point p = {0.0, 0.0};  // or Point p{};

// 6. Use designated initializers (C++20)
Point p = {.x = 1.0, .y = 2.0};

❌ Don't

// 1. Don't use C-style enums
enum Color { RED, GREEN, BLUE };  // Use enum class

// 2. Don't compare different enum types
// if (Color::Red == Direction::North)  // Won't compile with enum class βœ“

// 3. Don't rely on union type-punning (undefined behavior)
union { int i; float f; } u;
u.i = 42;
// float bad = u.f;  // UB! Use std::bit_cast or memcpy

// 4. Don't forget struct initialization
Point p;  // x and y are uninitialized garbage!

// 5. Don't use bit fields for portable binary formats
// (bit layout is implementation-defined)

Memory Comparison

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                   STRUCT vs UNION vs BIT FIELD                               β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                              β”‚
β”‚  STRUCT (sequential layout)              Size = sum of members + padding     β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                      β”‚
β”‚  β”‚ int a β”‚ int b β”‚     int c         β”‚   = 12 bytes                         β”‚
β”‚  β”‚(4 B)  β”‚(4 B)  β”‚     (4 B)         β”‚                                      β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                      β”‚
β”‚                                                                              β”‚
β”‚  UNION (overlapping)                     Size = largest member               β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                      β”‚
β”‚  β”‚ int a OR int b OR int c           β”‚   = 4 bytes                          β”‚
β”‚  β”‚         (4 B)                     β”‚                                      β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                      β”‚
β”‚                                                                              β”‚
β”‚  BIT FIELD (packed bits)                 Size = minimal for bits             β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                      β”‚
β”‚  β”‚ a:10 β”‚ b:10 β”‚ c:10 β”‚ pad:2        β”‚   = 4 bytes (32 bits)               β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                      β”‚
β”‚                                                                              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Cheat Sheet

// Enum class (preferred)
enum class Name : type { Value1, Value2 };
Name n = Name::Value1;
int i = static_cast<int>(n);

// Struct
struct Name {
    type member;
    type method() const { return member; }
};
Name obj = {value};
Name obj{value};

// Union (prefer std::variant)
union Name {
    type1 a;
    type2 b;
};

// std::variant (C++17)
std::variant<type1, type2> v;
std::get<type1>(v);
std::get_if<type1>(&v);
std::visit(visitor, v);

// Bit field
struct Name {
    type member : bits;
};

Compile & Run

g++ -std=c++17 -Wall -Wextra examples.cpp -o examples
./examples

# Check struct sizes
g++ -std=c++17 -Wall check_sizes.cpp -o check_sizes
./check_sizes