std::variant is a C++ standard-library type that stores exactly one value from a fixed list of possible types. If a program needs a value that can legally be an int, double, or std::string, a declaration such as std::variant<int, double, std::string> expresses that design directly. Unlike a traditional union, the variant also tracks which alternative is currently active, making it a type-safe discriminated union.
The type was added in C++17 through the <variant> header. The cppreference std::variant reference documents the current interface, while the original WG21 P0088R3 proposal describes the design goal: a type-safe union that makes the active alternative explicit and queryable.
Declaring and Assigning a Variant
#include <iostream>
#include <string>
#include <variant>
int main() {
std::variant<int, double, std::string> value;
value = 42;
value = 3.14;
value = std::string{"server-ready"};
}
A default-constructed variant contains its first alternative when that type can be default constructed. In the example above, value begins as an int containing zero. Later assignments replace the active alternative. This differs from OSC++.029 on std::optional: an optional models whether one type exists, while a variant models which one of several known types is active.
Checking the Active Type
std::variant<int, double, std::string> value = 42;
if (std::holds_alternative<int>(value)) {
std::cout << "integer\n";
}
std::cout << "active index: " << value.index() << '\n';
std::holds_alternative<T> asks whether the variant currently contains T. The index() member reports the zero-based alternative index. For std::variant<int, double, std::string>, index 0 means int, index 1 means double, and index 2 means std::string. Prefer type-based checks when the type itself communicates the design more clearly than an integer index.
Reading Values with get and get_if
std::variant<int, double, std::string> value = std::string{"ready"};
std::cout << std::get<std::string>(value) << '\n';
if (auto* text = std::get_if<std::string>(&value)) {
std::cout << *text << '\n';
}
std::get<T> returns the stored value when T is active, but throws std::bad_variant_access when the requested type is not active. std::get_if<T> is the non-throwing alternative: it returns a pointer to the value when the type matches and nullptr otherwise. The exception behavior connects directly with OSC++.015 on exception handling.
Using std::visit
std::visit is the central dispatch mechanism for variant-based code. Instead of manually checking every possible type, a visitor provides behavior for the active alternative. This can make state machines, protocol messages, parsed values, configuration data, and other closed sets of types easier to model.
#include <iostream>
#include <string>
#include <variant>
int main() {
std::variant<int, double, std::string> value = 3.14;
std::visit([](const auto& item) {
std::cout << item << '\n';
}, value);
}
The generic lambda above works because each listed type can be streamed with operator<<. More complex visitors can use overloaded lambdas or function objects to give each alternative different behavior. That approach is related to, but fundamentally different from, the virtual-function design introduced in OSC++.018 on runtime polymorphism: variant dispatch operates over a closed, compile-time list of possible types.
std::monostate and Default Construction
Sometimes none of the meaningful alternatives can be default constructed, or a program needs an explicit “nothing selected yet” state. std::monostate is a lightweight placeholder type for that purpose. A declaration such as std::variant<std::monostate, Config, Error> makes the first state intentionally empty-like while preserving variant semantics.
struct Config {
int port;
};
struct Error {
std::string message;
};
std::variant<std::monostate, Config, Error> state;
The valueless_by_exception State
A variant normally holds exactly one alternative, but the standard permits a rare valueless_by_exception state if replacing one alternative with another throws during certain operations. Production code that stores types with throwing move or construction behavior should understand this possibility. The earlier lessons on move operations and exception guarantees are especially important when variants contain resource-owning classes.
Compile and Run
g++ -std=c++17 -Wall -Wextra -pedantic variant_demo.cpp -o variant_demo
./variant_demo
The -std=c++17 flag is required because std::variant entered the standard library in C++17. Newer language modes such as C++20, C++23, or C++26 also provide the type, with later standards extending constexpr support and visitation capabilities.
Exercise
Create a program named sensor_value.cpp with std::variant<int, double, std::string>. Store an integer temperature reading, a floating-point voltage, and a string status one at a time. For each value, use std::visit to print both the value and a label describing its type. Then add one test using std::get_if so the program safely checks for a string without throwing.
Knowledge Check
- What problem does
std::variantsolve? - What does
holds_alternative<T>test? - What is the difference between
std::getandstd::get_if? - What does
std::visitdo? - Why might
std::monostatebe placed first in a variant? - What does
valueless_by_exception()report?
Answers
- It stores one value from a fixed set of possible types while tracking the active type safely.
- It reports whether the variant currently contains the requested type.
std::getreturns the requested alternative and can throw on a mismatch;std::get_ifreturns a pointer ornullptr.- It invokes a callable with the currently active alternative.
- It provides an explicit harmless default or empty-like state.
- It reports whether the variant currently holds no alternative because an exception interrupted a state-changing operation.
BitcoinVersus.Tech Editor’s Note:
We volunteer daily to ensure the credibility of the information on this platform is Verifiably True. If you would like to support to help further secure the integrity of our research initiatives, please donate using the QR code provided

For best QR-code scanning results, please scan this donation code from a desktop or larger screen. Mobile screens may prevent camera recognition.

Leave a Reply