C++17: new types: std::any, std::optional, std::variant

std::any

Any class can hold any type of object.  It’s type safe container for single values of any type.  A better way to handle any type and replace void*.

Type requeirments:

std::decay_t<T> – must be CopyConstructable

Example:

To get value from std::any you need to use std::any_cast.

In case if type in std::any_cast is wrong will be called std::bad_any_cast exception.

Exception hierarchy:

  • std::bad_any_cast -> std::bad_cast -> std::exception

Catch bad_any_cast example:

Implementations are encouraged to avoid dynamic allocations for small objects, but such an optimization may only be applied to types for which std::is_nothrow_move_constructible returns true.

any has own member functions:

has_value() – returns bool has it value or not

type() – returns std::type_info about object

reset() – drop object

emplace() – change object directly

To get know which type is inside std::any:

Usage example:

 

std::optional

std::optional it’s type which can represent nullable type. Optional means that value can be inside or cannot.

It’s common to avoid some return values like -1 , nullptr, NO_VALUE, etc or where data can be optional.

like:

For example:

and then we can check it, there is two methods:

value() – returns object

has_value() – is value exists

 

std::variant

std::variant it’s some kind of old c++ feature union, but it’s type safe and can hold complicated types, not only simple build-in types.

std::variant is not allowed to hold references, type void, arrays. variant do not use additional memory allocations in heap. Empty variant is also not allowed. variant can have same type more then once and with different cv.

Example:

In case getting wrong type from std::variant, std::bad_variant_access exception will be called.

If first type has no default constructor, it will be error while creating std::variant object.

For example:

to avoid this issue, you can use std::monostate.

 

Reading values from std::variant using std::visitor.

For example:

If you have the same interface for types, you can use generic lambda for access.

In this case, each type can be printed.

Also using std::variant it’s possible to create polymorphism without using v-table.

Example:

One interesting thing is overloading lambdas inside visitor:

and with variadic templates:

The overload struct is already purposed to C++20 standard.

Here is a paper: p0051r3

Leave a Reply

Your email address will not be published.