There are not only struct and class primitives in C++ that enable us to compose types. If we want to express that some variable can hold either some type A or a type B (or C, or whatever), we can use union. The problem with unions is that they cannot tell us they were actually initialized to which of the types that they can hold.
Consider the following code:
union U {
int a;
char *b;
float c;
};
void func(U u) { std::cout << u.b << 'n'; }
If we call the func function with a union that was initialized to hold an integer via member a, there is nothing that prevents us from accessing it, as if it was initialized to store a pointer to a string via member b. All kinds of bugs can be spread from such code. Before we start to pack our union with an auxiliary variable that tells us to what it was initialized in order to gain some safety, we can directly use std::variant, which came with C++17.
The variant is kind of the new-school, type-safe, and efficient union type. It does not use the heap, so it is as space-efficient and time-efficient as a union-based handcrafted solution could be, so we do not have to implement it ourselves. It can store anything apart from references, arrays, or the void type.
In this recipe, we will construct an example that profits from variant in order to get a feeling of how to use this cool new addition to the STL.