C++ std::variant vs std::any
Asked Answered
C

3

65

C++17 presents std::variant and std::any, both able to store different type of values under an object. For me, they are somehow similar (are they?).

Also std::variant restricts the entry types, beside this one. Why we should prefer std::variant over std::any which is simpler to use?

Campaign answered 25/5, 2019 at 10:25 Comment(8)
std::variant only works with a predefined set of types, while std::any literally goes with any type. It totally depends on your use cases, which of them is the better choice.Tamberg
@πάνταῥεῖ: What are predefined set of types?Campaign
Roughly speaking, the first one is compile-time, the second one is run-time.Illsuited
@deepmax The same what you expressed in your question stateing "restricts the entry types".Tamberg
std::variant is a template, std::any is not.Loot
no std::visit() for std::any; this, IMHO, should be a valid reason to prefer std::variant, when possible.Jenevajeni
It's like void* vs a union imoMiramirabeau
See also: C++ std::any vs std::variant vs std::optionalFoppery
H
116

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 variants (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".

Hailey answered 25/5, 2019 at 10:42 Comment(1)
Great explanation in one phrase: "any is a dressed-up void*. variant is a dressed-up union".Panhellenism
O
11

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 of T 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.

Outrank answered 25/5, 2019 at 10:32 Comment(0)
A
6

In addition to never using additional heap memory, variant has one other advantage:

You can std::visit a variant, but not any.

Alkyd answered 25/5, 2019 at 10:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.