Structs and Enumerations

A struct groups related values into one type; an enum class defines a type with a fixed set of named values. Together they let you model data directly — a Book with a title and a Genre — instead of juggling loose variables.

Structs

C++
#include <iostream>
#include <string>

struct Book {
    std::string title;
    std::string author;
    int year = 0;           // default member initialiser
    double price = 0.0;
};

int main() {
    Book b{"The C++ Programming Language", "Bjarne Stroustrup", 2013, 59.99};
    b.price = 49.99;
    std::cout << b.title << " by " << b.author << " (" << b.year << "), " << b.price << '\n';

    Book draft;                         // uses the defaults
    draft.title = "Untitled";
    std::cout << draft.title << ' ' << draft.year << '\n';
}
Output
The C++ Programming Language by Bjarne Stroustrup (2013), 49.99
Untitled 0

Members are accessed with a dot. Default member initialisers (int year = 0;) make sure members are never left uninitialised.

Designated initialisers

C++20 lets you name the members you initialise — clearer when a struct has many of them. They must appear in declaration order:

C++
#include <iostream>

struct WindowOptions {
    int width = 800;
    int height = 600;
    bool fullscreen = false;
    bool resizable = true;
};

int main() {
    WindowOptions opts{.width = 1280, .fullscreen = true};
    std::cout << opts.width << 'x' << opts.height << ", fullscreen " << opts.fullscreen << ", resizable " << opts.resizable << '\n';
}
Output
1280x600, fullscreen 1, resizable 1

Structured bindings

C++
#include <iostream>
#include <string>
#include <vector>

struct Score {
    std::string player;
    int points;
};

int main() {
    std::vector<Score> table{{"Ana", 120}, {"Ben", 95}};
    for (const auto& [player, points] : table) {
        std::cout << player << ": " << points << '\n';
    }
}
Output
Ana: 120
Ben: 95

Comparing structs

C++20 can generate comparison operators for you. Defaulting == compares every member; defaulting <=> gives all six comparisons in member order:

C++
#include <algorithm>
#include <compare>
#include <iostream>
#include <vector>

struct Version {
    int major = 0, minor = 0, patch = 0;
    auto operator<=>(const Version&) const = default;
};

int main() {
    std::vector<Version> versions{{1, 10, 0}, {1, 2, 3}, {2, 0, 0}, {1, 2, 10}};
    std::sort(versions.begin(), versions.end());
    for (const auto& v : versions) std::cout << v.major << '.' << v.minor << '.' << v.patch << ' ';
    std::cout << '\n' << std::boolalpha << (Version{1, 2, 3} == Version{1, 2, 3}) << '\n';
}
Output
1.2.3 1.2.10 1.10.0 2.0.0
true

enum class

A scoped enumeration defines its own type with named values. Its values must be written with the type name, and they don't silently turn into integers:

C++
#include <iostream>
#include <string_view>

enum class Genre { fiction, science, history, poetry };

std::string_view to_string(Genre g) {
    switch (g) {
        case Genre::fiction: return "fiction";
        case Genre::science: return "science";
        case Genre::history: return "history";
        case Genre::poetry:  return "poetry";
    }
    return "?";
}

int main() {
    Genre g = Genre::science;
    std::cout << to_string(g) << '\n';
    std::cout << static_cast<int>(g) << '\n';    // explicit conversion when you need the number
}
Output
science
1

An enum class can't be compared with an int or a value of another enum by accident:

C++
enum class Colour { red, green };
enum class Fruit { apple, lime };

int main() {
    Colour c = Colour::red;
    if (c == Fruit::apple) return 1;   // error: different types
    int n = c;                          // error: no implicit conversion
    return n;
}
Compiler error
main.cpp:6:11: error: invalid operands to binary expression ('Colour' and 'Fruit')
main.cpp:7:9: error: cannot initialize a variable of type 'int' with an lvalue of type 'Colour'

The older plain enum (without class) puts its names into the surrounding scope and converts to int freely — you'll see it in older code and C libraries. Prefer enum class. You can choose the underlying type: enum class Level : std::uint8_t { low, high };.

A struct with an enum

C++
#include <iostream>
#include <string>
#include <vector>

enum class Status { todo, doing, done };

struct Task {
    std::string title;
    Status status = Status::todo;
};

int main() {
    std::vector<Task> board{{"Design", Status::done}, {"Build", Status::doing}, {"Test"}};
    int open = 0;
    for (const auto& t : board) {
        if (t.status != Status::done) ++open;
    }
    std::cout << open << " of " << board.size() << " tasks still open\n";
}
Output
2 of 3 tasks still open

Try it yourself

Model playing cards with a Suit enum class and a Card struct, and print a small hand.

Try it yourself · main.cpp
Edit the code, copy it into main.cpp, then compile and run it with c++ -std=c++20 -Wall main.cpp -o main && ./main. How to set up a C++ compiler
Output
1 of spades
10 of hearts
12 of clubs