Both std::variant
and std::optional
are tools for representing values that may or may not be present, but they serve different purposes.
std::optional
is used to represent a value that may or may not exist. It's essentially a type-safe alternative to using a pointer to indicate the presence or absence of a value. An std::optional<T>
can either hold a value of type T
, or it can hold no value at all.
Here's an example:
#include <optional>
#include <iostream>
int main() {
std::optional<int> maybeInt = 42;
if (maybeInt.has_value()) {
std::cout << "Value: " << *maybeInt << '\n';
} else {
std::cout << "No value\n";
}
maybeInt = std::nullopt;
if (maybeInt.has_value()) {
std::cout << "Value: " << *maybeInt << '\n';
} else {
std::cout << "No value\n";
}
}
On the other hand, std::variant
is used to represent a value that can be one of several possible types. It's a type-safe union. A std::variant<T1, T2, ...>
holds a value that is one of the types T1
, T2
, etc.
Here's an example:
#include <variant>
#include <iostream>
using std::variant, std::holds_alternative,
std::string, std::get, std::cout;
int main() {
variant<int, string> v = 42;
if (holds_alternative<int>(v)) {
cout << "Int: " << get<int>(v) << '\n';
} else if (holds_alternative<string>(v)) {
cout << "String: " << get<string>(v) << '\n';
}
v = "hello";
if (holds_alternative<int>(v)) {
cout << "Int: " << get<int>(v) << '\n';
} else if (holds_alternative<string>(v)) {
cout << "String: " << get<string>(v) << '\n';
}
}
Int: 42
String: hello
So, the main difference is that std::optional
is used when you have a single type that may or may not have a value, while std::variant
is used when you have multiple possible types and the value is always one of those types.
Choose std::optional
when you have a value that may not exist, like the return value of a function that may not succeed, or a field in a struct that is not always filled in.
Choose std::variant
when you need to store a value that can be one of several different types, like a JSON value that could be a string, a number, a boolean, etc.
Of course, you can combine them: you can have a std::optional<std::variant<...>>
if you have a value that may or may not exist, and if it does exist, it could be one of several types.
Answers to questions are automatically generated and may not have been reviewed.
std::variant
Learn how to store dynamic data types in C++ using unions and the type-safe std::variant