How to print std::optional < T > for any T assuming `std::ostream << T()` is well defined?

Viewed 1365

I am trying to migrate an existing (largish) code base using boost::optional to use std::optional. BOOST has optional_io.hpp. No such thing exists for std::optional

This has to work with boost unit test as well

2 Answers

You could do something like this:

template<typename T>
std::ostream& operator<<(std::ostream& os, std::optional<T> const& opt)
{
    return opt ? os << opt.value() : os;
}

int main()
{
    std::optional<int> oi = 8;

    std::cout << oi << '\n';

    oi.reset();

    std::cout << oi << '\n';

    oi = 5;

    std::cout << oi << '\n';
}

Output:

8

5

Only print the value if it exists (then return the stream), otherwise just return the stream.

You could simply read optional_io.hpp and do the same thing. That said, they have chosen an approach that can be highly misleading. The following example illustrates the issue:

boost::optional<std::string> demo1 = "--";
boost::optional<std::string> demo2 = boost::none;
std::cout << demo1 << ' ' << demo2;

Output:

--  --

To reduce chance of confusion, I recommend something like this instead:

template<class Out, class T>
Out&
operator<<(Out& out, std::optional<T> const& v)
{
    if (v)
        out << "optional(" << *v << ')';
    else
        out << "nullopt";
    return out;
}

It doesn't solve all problems, but seems like a more reasonable default to me.

Related