C++ std::variant vs std::any
The more things you check at compile time the fewer runtime bugs you have.
variant
guarantees that it contains one of a list of types (plus valueless by exception). It provides a way for you to guarantee that code operating on it considers every case in the variant with std::visit
; even every case for a pair of variant
s (or more).
any
does not. With any
the best you can do is "if the type isn't exactly what I ask for, some code won't run".
variant
exists in automatic storage. any
may use the free store; this means any
has performance and noexcept(false)
issues that variant
does not.
Checking for which of N types is in it is O(N) for an any
-- for variant
it is O(1).
any
is a dressed-up void*
. variant
is a dressed-up union
.
any
cannot store non-copy or non-move able types. variant
can.
The type of variant
is documentation for the reader of your code.
Passing a variant<Msg1, Msg2, Msg3>
through an API makes the operation obvious; passing an any
there means understanding the API requires reliable documentation or reading the implementation source.
Anyone who has been frustrated by statically typeless languages will understand the dangers of any
.
Now this doesn't mean any
is bad; it just doesn't solve the same problems as variant
. As a copyable object for type erasure purposes, it can be great. Runtime dynamic typing has its place; but that place is not "everywhere" but rather "where you cannot avoid it".
The difference is that the objects are stored within the memory allocated by std::variant
:
cppreference.com - std::variant
As with unions, if a variant holds a value of some object type
T
, the object representation ofT
is allocated directly within the object representation of the variant itself. Variant is not allowed to allocate additional (dynamic) memory.
and for std::any
this is not possible.
As of that a std::variant
, does only require one memory allocation for the std::variant
itself, and it can stay on the stack.
In addition to never using additional heap memory, variant
has one other advantage:
You can std::visit
a variant
, but not any
.