This article introduces the new std::any
class in C++ 17. It can store all values that are “Copy Constructible”. In the following we will first introduce the basic usage of std::any
, and then describe the practical use of it.
Usage
The use of the std::any
class is broken down as follows.
- Constructed objects
- Assigning operators
- any_cast function
- has_value member function
- reset member function
- emplace member function
- type member function
Constructed objects
The std::any
category is defined in the <any>
header file. There are several ways of constructing std::any
objects.
- construct a
std::any
object without a value using the Default Constructor. - pass the value to the
std::any
constructor so that it stores the value. - construct a
std::any
object “with the value ofValueType
” with thestd::make_any<ValueType>
function. The arguments tostd::make_any
are passed to the constructors ofValueType
.
Regardless of how the std::any
object is constructed, the value stored must be Copy Constructible
. For example, if we try to pass a non-copyable std::unique_ptr
object into the std::any
construct, we get the following compilation error.
Assigning operators
We can replace the values stored in std::any
by assigning operators. The type of value can also be changed at will.
We can also assign one std::any
object to another std::any
object.
any_cast function
The values stored by std::any
must be read in the std::any_cast
style function. Because we must pass in the stencil argument of std::any_cast
, we must know the type of the value stored in std::any
. If the type of the template parameter is different from the type of the std::any
stored value, std::any_cast
will throw the following exception to std::bad_any_cast
.
If the std::any_cast
object passed to std::any_cast
is a reference type, std::any_cast
will return a copy of the stored value.
If we want direct access to the values in the std::any
object, the argument type of std::any_cast
must be std::any *
(pointer type). Example.
|
|
has_value member function
The has_value
member function returns whether std::any
has the value.
reset member function
The reset
member function clears the values stored in std::any
.
emplace member function
emplace<ValueType>(...)
The member function constructs a value of type ValueType
within the std::any
object. The argument of emplace
becomes the argument of the ValueType
construct. If the std::any
object already has a value, the existing value will be deconstructed first.
Although emplace<ValueType>(...)
and operator=(ValueType(...))
is similar to operator=(ValueType(...)
, but if the Copy Constructor (or Move Constructor) of ValueType
has to take longer to execute, emplace<ValueType>(...)
can save us the execution time of copying (or moving) objects from a ValueType
temporary object.
type member function
The type
member function returns Run-Time Type Information (RTTI) for a numeric type. The type
member function and the typeid
keyword are used to select the appropriate std::any_cast
function template parameter for the run-time. If the std::any
object has no value, the type
member function will return typeid(void)
.
|
|
Context of use
When designing APIs, we often have to keep their Context Object for the Callback function. The Context Object is then passed to the Callback function when it is called. However, we run into two problems at this point:
- The party holding the Context Object does not want to impose too many restrictions on the Context Object, nor does it want to know the type of the Context Object.
- The party holding the Context Object must know how to deconstruct the Context Object.
The class std::any
solves these two problems elegantly. A simple example is the following.
|
|
In practice, EventSource
, callback1
and callback2
will belong to separate C++ source files. The EventSource
does not need to know the actual type of the Context Object. Each Callback will obtain its own Context Object via std::any_cast
according to its own logic after getting the std::any
object.
Reference
- cppreference.com, std::any