I tried to iterate over an std::optional
:
for (auto x : optionalValue)
{
...
}
With the expectation of it doing nothing if optionalValue
is empty but doing one iteration if there is a value within, like it would work in Haskell (which arguably made std::optional
trendy):
forM optionalValue
( \x ->
...
)
Why can't I iterate an optional? Is there another more standard C method to do this?
CodePudding user response:
std::optional
does not have a begin()
and end()
pair. So you cannot range-based-for over it. Instead just use an if
conditional.
See Alternative 2 for the closest thing to what you want to do.
Edit: If you have a temporary from a call result you don't have to check it explicitly:
if (auto const opt = function_call()) {
do_smth(*opt);
}
The check for static_cast<bool>(opt)
is done implicitly by if
.
Alternative 1
Another alternative is to not use an std::optional<T>
but std::variant<std::monostate, T>
. You can then either use the overloaded
idiom or create a custom type to handle the monostate:
template <typename F>
struct MaybeDo {
F f;
void operator()(std::monostate) const {}
template <typename T>
void operator()(T const& t) const { f(t); }
};
which will allow you to visit the value with some function:
std::variant<std::monostate, int> const opt = 7;
std::visit(MaybeDo{[](int i) { std::cout << i << "\n"; }}, opt);
Alternative 2
You can also wrap optional in a thing that allows you to iterate over it. Idea:
template <typename T>
struct IterateOpt {
std::optional<T> const& opt;
struct It {
std::optional<T> const* p;
It& operator () {
p = nullptr;
return *this;
}
It operator (int) {
return It{nullptr};
}
auto const& operator*() const { **p; }
};
auto begin() const {
if (opt) return It{&opt};
else end();
}
auto end() const {
return It{nullptr};
}
};
This is a crude sketch of how to do this and probably requires some love to work on different situations (like a non-const optional).
You can use this to "iterate" over the optional:
for (auto const& v: IterateOpt{function_call()}) {
do_smth(v);
)