std::variant

C++
Author

Quasar

Published

December 23, 2025

Using std::variant

A std::variant is a closed-discriminated union. Variants simply have internal memory for maximum size of the underlying types plus a fixed overhead to manage which alternative is used. No heap memory is allocated. The resulting object has value semantics. Copying a variant is implemented as a deep-copy, it creates a new variant object with the current value of the alternative in its own memory.

#include <iostream>
#include <variant>
#include <string>

int main(){
    // initialized with string alternative
    std::variant<int, std::string> var{"hi"};   
    std::cout << var.index() << "\n";

    // now holds int alternative
    var = 42;
    std::cout << var.index() << "\n";

    try{
        int i = std::get<0>(var);  // access by index
        int j = std::get<int>(var); //access by type
        std::string s = std::get<std::string>(var); //error
    }catch(const std::bad_variant_access& e){
        std::cerr << "Exception: " << e.what() << "\n";
    }
    return 0;
}

Compiler Explorer

Output:

Program returned: 0
Program stdout

1
0

Program stderr

Exception: std::get: wrong index for variant

The default constructor for std::variant always initializes the first type with the default constructor. If there is no default constructor for the first type, calling the default constructor for the variant is a compile-time error.

To support variants, where the first type has no default constructor, a special helper type is provided: std::monostate. Objects of type std::monostate always have the same state.