Article by Ayman Alheraki on January 11 2026 10:37 AM
std::variant and std::optional
Modern C++ continues to evolve in power, clarity, and expressiveness. Two key tools in this evolution are std::variant and std::optional — both part of the type-safe union and nullable value family, introduced in C++17 and significantly refined in C++20 and C++23.
This article presents a comprehensive guide to the improvements made to these utilities in C++20 and C++23, highlighting real-world use cases, best practices, and what every serious C++ developer should know.
std::optional: Enhancements in C++20 and C++23std::optional?std::optional<int> maybe_value = get_value();if (maybe_value) { std::cout << "Value: " << *maybe_value << '\n';}Represents an optional value, similar to Option in Rust or Maybe in Haskell.
Avoids the pitfalls of null pointers and exception-based returns.
std::optionalconstexpr Support
You can now use std::optional in constexpr contexts, enabling powerful compile-time evaluations.
constexpr std::optional<int> square(int x) { return x > 0 ? std::optional{x * x} : std::nullopt;}static_assert(square(5).value() == 25);Three-Way Comparison (<=>)
std::optional now supports the spaceship operator for consistent and simplified comparison behavior.
std::optional<int> a = 10, b = 20;if (a < b) { std::cout << "a < b"; }Monadic Interfaces (proposed)
Although not standardized yet, monadic functions like and_then, transform, and or_else are being explored to simplify functional-style chaining.
Potential future syntax:
maybe_value.and_then([](int v) { return do_something(v); });Improved Debugging and Diagnostics
C++23 improves error messages and constexpr feedback when using std::optional, particularly in template-heavy code.
std::variant: Powerful Type-Safe Unionstd::variant?std::variant<int, std::string> data;data = 42;data = "text";A type-safe alternative to traditional unions.
Enables runtime polymorphism without inheritance.
Excellent for APIs where a value may be one of multiple known types.
std::variantconstexpr Construction and Access
Now fully usable in compile-time contexts.
constexpr std::variant<int, float> v = 42;static_assert(std::holds_alternative<int>(v));std::visit Becomes constexpr
Visitors can now be evaluated at compile time.
constexpr int result = std::visit([](auto x) { return x + 1;}, std::variant<int>{5});static_assert(result == 6);Improved Exception Guarantees
More operations are marked noexcept, improving exception safety and performance.
Clearer Diagnostics Template instantiation errors involving variants are now easier to understand.
Better Overload Inference in std::visit
Supports complex lambdas and deduced overloads more gracefully, reducing the need for boilerplate.
Library Conformance and Future Compatibility Implementation consistency ensures smoother upgrades and enables future enhancements like reflection and pattern matching.
Configuration Parsing
Use std::variant to represent config values that could be int, bool, or string.
Command Results
Use std::optional<T> to represent success/failure without exceptions or error codes.
Serialization Layers
std::variant maps well to formats like JSON, YAML, or TOML where values can be heterogeneously typed.
| Mistake | Better Approach |
|---|---|
Using .value() unsafely | Check .has_value() or use if (opt) |
Skipping std::visit | Always use std::visit to access variant values |
| Using heavy types in variants | Use smart pointers inside the variant |
The next wave of improvements may include:
Pattern Matching (expected in C++26)
Standardized Monadic Interfaces for optional and expected
Reflection to make generic programming safer and cleaner
Better Codegen as compilers optimize for variant layout and visitation
With std::optional and std::variant, Modern C++ provides elegant, type-safe alternatives to nullptr, unions, and verbose error handling. The enhancements in C++20 and C++23 bring compile-time power, safer APIs, and cleaner control flow to every C++ codebase.
If you're writing modern C++, these tools are not optional — they are essential. Understanding their capabilities, limitations, and best practices is a mark of true professionalism in contemporary C++ software development.