It is sometimes useful to treat an optional type as being a range with either one or zero elements. Rust has this feature, by making std::option implement IntoIterator. In C++ this would mean implementing overloads of std::begin and std::end taking std::optional<T> (and const std::optional) with :
std::next(std::begin(op)) == std::end(op)
if o.has_value(), and
std::begin(op) == std::end(op)
otherwise.
This would mostly be for piping a range of optionals into std::join to leave just the unwrapped values, as in:
std::vector<std::optional<int>> opts = {1, 2, std::nullopt,
std::nullopt
, 3 };
for(int n : opts | std::join )
std::cout << n << " , ";
This has the benefit of avoiding the programmer having to call has_value() and value() explicitly, which I think is probably for the best in terms of safety.