Variant

In C++, std::variant is a type-safe, generic container that can hold one value out of a set of specified types. It was introduced in C++17 as part of the Standard Library and is defined in the <variant> header. std::variant can be thought of as a type-safe union that allows you to store different types of values but only one type at a time.

Key Features of std::variant

  1. Type-Safety: Unlike traditional unions, std::variant is type-safe, meaning it keeps track of the type of the value currently stored in it and ensures that only valid operations are performed.

  2. Multiple Types: std::variant can hold any one of the types specified in its template parameters. For example, std::variant<int, float, std::string> can hold either an int, a float, or a std::string.

  3. Visitors and std::visit: To safely retrieve and work with the value stored in a std::variant, you can use std::visit along with a visitor function or lambda.

  4. Exceptions: If you attempt to retrieve a value of a type that is not currently stored in the variant, an exception (std::bad_variant_access) will be thrown.

Basic Usage of std::variant

1. Including the Header

To use std::variant, you need to include the <variant> header:

cppCopy code#include <variant>

2. Declaring a std::variant

You can declare a std::variant that can hold any one of several types:

cppCopy codestd::variant<int, float, std::string> v;

This variant v can hold an int, a float, or a std::string, but only one of them at any given time.

3. Assigning a Value

You can assign a value of any of the specified types to the std::variant:

cppCopy codev = 42;          // v now holds an int
v = 3.14f;       // v now holds a float
v = "Hello";     // v now holds a std::string

4. Accessing the Value

To access the value stored in a std::variant, you can use std::get:

If the variant does not currently hold the requested type, std::get throws std::bad_variant_access:

5. Checking the Active Type

You can check which type is currently held by the std::variant using std::holds_alternative:

Alternatively, you can use std::visit to apply a visitor function or lambda to the currently held value:

Example: Using std::variant

Here’s an example that demonstrates how to use std::variant:

Output:

Explanation:

  1. Variant Declaration:

    • std::variant<int, float, std::string> v; declares a variant v that can hold either an int, a float, or a std::string.

  2. Assigning Values:

    • v = 42; assigns an int to v.

    • v = 3.14f; assigns a float to v.

    • v = "Hello, World!"; assigns a std::string to v.

  3. Using std::visit:

    • std::visit(PrintVisitor{}, v); applies the PrintVisitor to the value currently held by v, printing it according to its type.

Advanced Features of std::variant

1. Default Value and Alternative Index

You can specify which alternative is the default using std::variant_alternative:

You can also retrieve the index of the currently held type:

2. Monostate

If you want to include an "empty" state in your variant, you can use std::monostate:

When to Use std::variant

  • Polymorphism: When you need a type-safe way to hold one of several types in a single variable, and you don't want to use inheritance or pointers.

  • Function Return Types: When a function can return different types based on conditions.

  • Union Replacement: When you need the flexibility of a union but with type safety.

Conclusion

std::variant in C++ provides a powerful, type-safe alternative to traditional unions, allowing you to store and manipulate one value from a set of types. With std::variant, you can safely handle different types in a single variable and make your code more robust and easier to maintain. It is particularly useful in situations where a variable can hold one of several types and when you want to ensure type safety and avoid errors related to manual type management.

Last updated