Reputation: 402
Is there a reasonably idiomatic way* to use stream insertion operators >>
with std::optional
? The standard class does not provide an overload for std::istream& operator>>(std::istream& is, std::optional<T>& obj)
, and I believe using
std::optional<int> i{};
stream >> *i;
invokes undefined behavior if i
does not already have a value.
*Yes I am aware that nothing about streams is idiomatic or natural...
Upvotes: 2
Views: 211
Reputation: 402
Inspired by @Jan Schultke's answer, one could also provide a definition for operator>>
:
template<typename T>
std::istream& operator>>(std::istream& is, std::optional<T>& obj)
{
if (T result; is >> result) obj = result;
else obj = {};
return is;
}
//...
std::optional<int> i;
std::cin >> i;
However, it is unclear to me if defining such a function which acts purely on Standard Library types is allowed by the Standard. (At least here It seems that doing this is allowed, but may be a questionable practice.operator>>
is not in the std::
namespace.)
Upvotes: 1
Reputation: 39804
You're right. *i
is undefined behavior for an empty std::optional
.
What you should do instead is:
auto i = [&stream] -> std::optional<int> {
int result;
if (stream >> result) return result;
else return {};
}();
Instead of an immediately-invoked lambda expression (IILE), you could also write a utility function that does this for you:
template <typename T>
std::optional<T> try_read(std::istream& stream) {
T result;
if (stream >> result) return result;
else return {};
}
// ...
std::optional<int> i = try_read<int>(stream);
Upvotes: 1