std::variant
is a C++ template class introduced in the C++17 standard, offering a type-safe union. In simpler terms, it enables us to store values of different types in a single variable. Unlike traditional unions, which can only hold one type at a time, std::variant
provides a safe and expressive way to work with variant types.
std::variant
Using std::variant
is quite straightforward. We just need to include the <variant>
header in our code and then we can declare a variant using the template syntax, specifying the types it can hold.
std::variant
std::variant
is a template class that can hold values of different types. The types it can hold are specified within the angle brackets. In the example below, myVariant
can hold values of Type1
, Type2
, or Type3
.
std::variant<Type1, Type2, Type3, ...> myVariant;
Let’s look at the code below:
#include <variant>#include <iostream>#include <string>int main() {std::variant<int, double, std::string> myVariant;// Assigning valuesmyVariant = 42; // intmyVariant = 3.14; // doublemyVariant = "Hello, C++"; // std::string// Accessing valuesif (std::holds_alternative<int>(myVariant)) {std::cout << "It's an integer: " << std::get<int>(myVariant) << std::endl;} else if (std::holds_alternative<double>(myVariant)) {std::cout << "It's a double: " << std::get<double>(myVariant) << std::endl;} else if (std::holds_alternative<std::string>(myVariant)) {std::cout << "It's a string: " << std::get<std::string>(myVariant) << std::endl;}return 0;}
In the example above, myVariant
can hold values of type int
, double
, or std::string
. We can assign values and later check which type it currently holds using std::holds_alternative
and retrieve the value with std::get
.
Let’s look at the code below:
#include <variant>#include <iostream>#include <string>int main() {std::variant<int, double, std::string> myVariant;// Assigning valuesmyVariant = 42; // intmyVariant = 3.14; // doublemyVariant = "Hello, C++"; // std::string// Extract the index of the currently held typestd::cout << "Type index: " << myVariant.index() << std::endl;// Check if the variant is valueless (has not been assigned a value)bool isValueless = myVariant.valueless_by_exception();std::cout << "Is valueless: " << std::boolalpha << isValueless << std::endl;return 0;}
Line 14: In the code above, myVariant.index();
indicates the position of the active alternative in the variant type list.
Line 17: myVariant.valueless_by_exception();
checks whether the variant is valueless, meaning it has not been assigned any value.
Line 18: std::cout << "Is valueless: " << std::boolalpha << isValueless << std::endl;
prints the boolean result of whether myVariant
is valueless or not. The std::boolalpha
manipulator is used to print true
or false
instead of 1
or 0
.
std::variant
?std::variant
provides a type-safe alternative to traditional unions, reducing the risk of runtime errors associated with type mismatches. It also facilitates code readability by explicitly specifying the types a variable can hold. This can be particularly useful in scenarios where we want to represent a choice between different types, such as in parsers, state machines, or other polymorphic scenarios.
std::variant
also opens up new possibilities for handling diverse types within our programs. It promotes type safety and helps us write cleaner, more expressive code.