What is std::variant in C++?
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.
How to use 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.
Syntax for 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;
Code example
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.
Additional example methods
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;}
Code explanation
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 whethermyVariantis valueless or not. Thestd::boolalphamanipulator is used to printtrueorfalseinstead of1or0.
Why use 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.
Free Resources