The following structures are described in A Tour of C++ (second edition) as alternatives where they could be specified to store one or set of alternatives types. There are variant
, optional
and any
imported from standard libraries <variant>
, <optional>
and <any>
respectively which are available in C++17.
variant
A variant
could be defined and used as follows:
std::variant<int, bool> x;
// ...
auto y = std::get<bool>(x);
From above, x
could hold either an int
or a bool
value, which closely resembles a union
but safer. To get the value from a variant
, we can use std::get
with a template parameter that specified which type should be retrieved.
optional
An optional
could be defined as follows:
std::optional<int> x = 12; // x contains 12
std::optional<int> y = {}; // y is empty
It can either hold a value or be empty by initialise it as {}
. In convention, optional
should be treated as a pointer to the object rather as an object. This means that x
as defined above should be understood as a pointer to an int
value which its value is 12. Additionally, *
operator on optional
to get the value of the variable and the fact that {}
is basically the equivalent to nullptr
should be able to convince programmers to treat them as so.
Note: Accessing an optional
that does not hold a value will result in undefined behaviour, thus renders it as type unsafe.
any
An any
could be defined and used as follows:
std::string str = "Hello World!";
std::any message = str;
// ...
std::string recipient = std::any_cast<string>(message);
It could hold any type of value and be later cast by the function std::any_cast
. That being said, any
can only hold one type of value throughout its lifetime until either it is out of scope or it has called make_any
to allocate another any
to itself.