std::variant in C++ 17

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.