std::optional and std::variant
intermediate30 min readLesson 104 of 204
Absence without sentinels, sum types with visit, and honest signatures for parse-style results.
std::optional<T> is a T that may be absent โ the vocabulary type for
"maybe no value" without sentinel magic (-1, nullptr, empty string).
#include <optional>
std::optional<int> find_index(const std::vector<int>& v, int target) {
for (std::size_t i = 0; i < v.size(); ++i)
if (v[i] == target) return static_cast<int>(i);
return std::nullopt;
}
auto idx = find_index(v, 7);
if (idx.has_value()) use(*idx); // or idx.value() (throws if empty)
int fallback = idx.value_or(-1); // read with a default
std::variant<A, B> is a type-safe union: it holds exactly one of the
alternatives, and std::visit dispatches on which one:
#include <variant>
std::variant<int, std::string> result = 42;
result = std::string{"overflow"};
auto text = std::visit([](auto&& x) {
using T = std::decay_t<decltype(x)>;
if constexpr (std::is_same_v<T, int>) return std::to_string(x);
else return x;
}, result);
Choose optional when the question is "is there a value?"; choose
variant when the answer is "one of several different types" โ parse
results, state machines, tagged outputs. Both replace error-channel
out-parameters and make signatures honest.