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?

If you have a std::variant that contains types that are not default-constructible, you can still default construct the variant by including std::monostate as one of the variant's alternative types.

std::monostate is a special type designed for this purpose. It's an empty struct that is always default-constructible. By including it as the first alternative in your variant, you ensure that the variant itself is default-constructible, even if the other types are not.

Here's an example:

#include <variant>

struct NonDefaultConstructible {
  NonDefaultConstructible() = delete;
  NonDefaultConstructible(int x) {}
};

int main() {
  // This fails because NonDefaultConstructible
  // is not default-constructible
  std::variant<NonDefaultConstructible> v;

  // This works because std::monostate is
  // default-constructible
  std::variant<std::monostate,
    NonDefaultConstructible> v;

  // You can still emplace other types
  v.emplace<NonDefaultConstructible>(42);
}
error: 'std::variant<NonDefaultConstructible>::variant': no appropriate default constructor available

When you default construct a variant with std::monostate, the variant will initially hold a std::monostate value. You can then assign or emplace one of the other types into the variant as needed.

Keep in mind that std::monostate is a distinct type, so you need to handle it in your visitor functions or when retrieving values from the variant. But it's a small price to pay for the ability to default construct variants with non-default-constructible types.

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?
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?
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