In the world of modern C++ programming, the std::variant is a powerful tool that allows you to work with multiple data types in a flexible and type-safe manner. In this article, we will discuss std::variant and explore its fundamentals, applications, and benefits with practical code examples.
Prerequisites: C++ data types, functions, unions, and classes.
What is std::variant?
A variant is a data type introduced in C++ 17 that can hold values of different types, much like a union in C. However, std::variant brings type safety to the table, making it a safer and more versatile alternative.
How Does std::Variant Work?
At its core, std::variant is a union of types. It can store one value at a time from a predefined set of types. Unlike a traditional union, std::variant keeps track of its active type, ensuring that you access the correct value.
Types Supported by std::Variant
std::variant can hold values of various data types, including fundamental types (int, double, etc.), user-defined types (custom classes or structs), and even other variants. This flexibility opens up a world of possibilities for handling complex data scenarios.
Syntax of std::variant
std::variant <Types...> var_name;
where,
- Types: All possible type of data that the variant may have to store.
- var_name: variant object name.
Methods Associated with std::variant
Some methods associated with std::variant to provide different facilities. Some of them are as follows:
S.No
| Method
| Description
|
---|
1
| index() | Returns the index of the type of data stored in the variant. |
---|
2
| emplace() | In place construction of the value of the variant. |
---|
3
| holds_alternative() | Check if the given type of data is stored inside the variant at the given moment in time. |
---|
4
| get() | It retrieves the value of the given type or index from the variant. |
---|
Examples of std::variant
Let's illustrate the std::variant with some code examples.
Example 1
C++
// C++ Program to illustrate std::variant
#include <iostream>
#include <string>
#include <variant>
using namespace std;
int main()
{
variant<int, double, string> myVariant;
myVariant = 42; // Assign an int
// Access the int
if (holds_alternative<int>(myVariant)) {
cout << get<int>(myVariant) << endl;
}
myVariant = 3.14; // Assign a double
// Access the double
if (holds_alternative<double>(myVariant)) {
cout << get<double>(myVariant) << endl;
}
myVariant = "Hello, Variant!"; // Assign a string
// Access the string
if (holds_alternative<string>(myVariant)) {
cout << get<string>(myVariant) << endl;
}
return 0;
}
Output
42
3.14
Hello, Variant!
Example 2
C++
// C++ Program to illustrate std::variant
#include <iostream>
#include <variant>
using namespace std;
// Define custom data types
struct Circle {
double radius;
};
struct Square {
double side;
};
// driver code
int main()
{
variant<Circle, Square> shapeVariant;
// Create a Circle
shapeVariant = Circle{ 5.0 };
// Check the active type and perform operations
// accordingly
if (holds_alternative<Circle>(shapeVariant)) {
Circle c = get<Circle>(shapeVariant);
cout << "Circle with radius: " << c.radius << endl;
}
else if (holds_alternative<Square>(shapeVariant)) {
Square s = get<Square>(shapeVariant);
cout << "Square with side: " << s.side << endl;
}
else {
// Handle the case where the variant does not
// contain either a Circle or a Square
cout << "Unrecognized shape" << endl;
}
return 0;
}
Output
Circle with radius: 5
Applications of std::Variant
Following are some main applications of the std::variant:
- Handling Multiple Data Types: One of the most common use cases for std::variant is when you need to work with functions or classes that can accept different data types. Instead of writing multiple overloads, you can use a variant to streamline your code and make it more maintainable.
- State Machines: State machines, a crucial concept in software engineering, often require managing different states and transitions. std::variant simplifies this by allowing you to represent states as types and transitions as functions, resulting in clean and efficient code.
Similar Reads
std::make_unique in C++ 14 std::make_unique is a utility function in C++ that was introduced in C++14. It is used to create a unique_ptr object, which is a smart pointer that manages the lifetime of dynamically allocated objects. It is defined inside <memory> header file. Syntaxstd::make_unique <object_type> (argu
2 min read
C++ 11 Standard C++ 11, officially known as ISO/IEC 14882:2011, is a significant version of the C++ programming language standard, published in 2011. It marked a major fix up of the language, introducing various features and enhancements that improved the usability, performance, and safety of C++ code. Before C++ 1
5 min read
if constexpr in C++ 17 In C++17, if constexpr feature was introduced to allow compile-time branching based on constant expressions. Unlike regular if statements, which are evaluated at runtime, the if constexpr allows the compiler to discard branches of code that do not apply. It means only the branch of code for which th
3 min read
Fold Expressions in C++ 17 Fold expressions in C++17 are a powerful feature that allows you to reduce or "fold" a parameter pack over a binary operator. They were introduced to simplify code that operates on variadic templates and make it more concise and readable. Syntax Fold expressions have the following syntax forms: (pac
4 min read
Trailing Return Type in C++ 11 The trailing return type syntax, a new method of indicating a function's return type, was introduced in C++11. Before C++11, the return type of a function was typically specified before the function name. However, in some cases, it could be challenging to express complex return types, especially whe
2 min read