Stream insertion operator >> for std::optional

141 Views Asked by At

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...

2

There are 2 best solutions below

5
Jan Schultke On

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);
3
kc9jud On

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 operator>> is not in the std:: namespace.) It seems that doing this is allowed, but may be a questionable practice.