What is the difference between std::variant and std::any?

How does std::variant differ from std::any in C++? When would I use one over the other?

Both std::variant and std::any are used for storing values of different types, but they serve different purposes and have different characteristics.

std::variant is a type-safe union. It can hold a value of one of a fixed set of types, which are specified at compile-time as template arguments. The key characteristics of std::variant are:

  1. Type safety: You can only access the value in a variant through a visitor or by explicitly specifying the expected type. This prevents accessing data as the wrong type.
  2. Fixed set of types: The types a variant can hold are fixed at compile-time. You can't add new types at runtime.
  3. No heap allocations: variants usually store their values directly in the variant object (though some large types may be heap-allocated).

On the other hand, std::any is a type-erasing container. It can hold a single value of any type. The type of the value is erased and not known at compile-time. Key characteristics of std::any are:

  1. Runtime polymorphism: You can store any type in an any, even types that weren't known when the any was created.
  2. Type erasure: The type of the stored value is not known at compile-time. You need to cast the value back to its original type to use it.
  3. Heap allocation: any typically allocates the stored value on the heap.

Use std::variant when you have a fixed set of types and want type-safety and avoid heap allocations. For example:

#include <variant>
#include <iostream>

auto Visitor{[](auto&& arg) {
  constexpr bool isInt{std::is_same_v<
    std::decay_t<decltype(arg)>, int>};
  constexpr bool isString{std::is_same_v<
    std::decay_t<decltype(arg)>, std::string>};

  if constexpr (isInt) {
    std::cout << "int: " << arg << '\n';
  } else if constexpr (isString) {
    std::cout << "string: " << arg << '\n';
  }
}};

int main() {
  std::variant<int, std::string> v = 42;
  std::visit(Visitor, v);
}
int: 42

Use std::any when you need to store any type and only know what type you're storing at runtime. For example:

#include <any>
#include <iostream>

int main() {
  std::any a = 42;
  a = std::string("hello");
  std::string& s = std::any_cast<
    std::string&>(a);
  std::cout << s;  // prints "hello"
}
hello

In summary, use std::variant for type-safe value-based polymorphism, and std::any for type-erasing runtime polymorphism.

Constrained Dynamic Types using Unions and std::variant

Learn how to store dynamic data types in C++ using unions and the type-safe std::variant

Questions & Answers

Answers are generated by AI models and may not have been reviewed. Be mindful when running any code on your device.

When should I use std::variant instead of a union?
What are the advantages of using std::variant over a regular union in C++? When is it better to use std::variant?
How can I default construct a variant with non-default-constructible types?
If I have a std::variant with types that are not default-constructible, how can I still default construct the variant?
How do I handle errors when using std::variant?
What are the best practices for error handling when using std::variant in C++? How do I deal with exceptions and invalid accesses?
What are the performance characteristics of std::variant?
How does std::variant perform compared to other ways of storing multiple types, like unions or inheritance? Are there any performance pitfalls to watch out for?
How can I define a recursive variant type?
Is it possible to have a variant that contains a type that itself contains the same variant type? How would I define such a recursive variant?
What is the difference between std::variant and std::optional?
How does std::variant differ from std::optional in C++? When would I choose to use one over the other?
Or Ask your Own Question
Get an immediate answer to your specific question using our AI assistant