C++ 타입 선택 조언: struct·class·enum·variant 언제 쓰나 (Tour 2.6)

Short answer: When built-in types are insufficient in C++, design and choose the appropriate user-defined type (struct, class, enum, variant) to group related data and prevent invalid states.

This post follows the A Tour of C++ 2.6 Advice study notes. It summarizes how to use struct, class, enum, union, and variant, which were introduced earlier in Chapter 2 (User-Defined Types), and it does not re-explain union memory layout from 2.5 Unions from scratch.

When should you choose struct, class, enum, or variant?

Short answer: Use struct to group related data, class when you want to hide implementation and expose only an interface, enum class for a fixed set of named states, and std::variant when you need to hold one of several types in a type-safe way.

If built-in types like int and double can’t express meaning clearly enough, define a type that makes the meaning explicit. The study notes give this example:

struct Celsius {
    double value;
};

Celsius expresses the meaning of the value far more clearly than a plain double temperature. Related values should be grouped into one concept rather than managed separately.

struct Point {
    double x;
    double y;
};

When you want to expose only the necessary interface and hide the implementation, use class instead.

class Counter {
public:
    void increment();
private:
    int value = 0;
};

A struct can be thought of as a class whose default access level is public. In the example below, A::x is public and B::x is private.

struct A {
    int x;   // public
};
class B {
    int x;   // private
};

For a set of named constants, use enum class instead of representing state directly as 0, 1, 2.

enum class State {
    idle,
    running,
    error
};

choosing between struct, class, enum, and variant

choosing between struct, class, enum, and variant

Why prefer std::variant over a naked union?

Short answer: Unlike a naked union, which forces the programmer to track state manually, std::variant tracks which type is currently active on its own, guaranteeing type safety.

Using a union directly means the programmer has to track which member is the active one.

union Value {
    int i;
    double d;
};

If needed, a tag and a union can be combined inside a class to manage state, but wherever possible, prefer std::variant over a naked union.

std::variant value;

std::variant manages which type is currently held on its own, making it more type-safe than a raw union. It’s also better to define operations that match the meaning of an enum or variant, rather than treating a state value as a plain number.

naked union vs std::variant

naked union vs std::variant

What core design philosophy does 2.6 Advice teach?

Short answer: Define types that clearly express the meaning of your data, and design them — for example through constructors — so that objects are guaranteed to be in a valid state from the moment they are created.

class User {
public:
    User(int id) : id{id} {}
private:
    int id;
};

The core philosophy of Chapter 2 is to represent the meaning of data through types, and to design those types so invalid states are hard to create. Comparing these two snippets shows the difference:

// bad
int status = 0;

// good
enum class Status { idle, running, error };
Status status = Status::idle;

With int status, the type alone tells you nothing about which values are valid or what each number means. enum class Status, on the other hand, restricts the value to a named set of possible states, so an undefined value can’t be assigned in the first place. Choosing struct, class, enum, or variant to fit the purpose is the core message of 2.6 Advice.

FAQ

Q. What’s the difference between struct and class?

A. The default access level differs. struct defaults to public, while class defaults to private. Choose whichever fits the purpose.

Q. Why is enum class recommended over using a plain int to represent state?

A. enum class makes the code’s intent explicit and prevents name collisions and unintended implicit conversions to integers, leading to safer code.

Sources

C++ study notes — 2.6 Advice

cppreference: enum

cppreference: std::variant