C++ Logo


Advanced search

Re: [std-proposals] Add operator>> overloads to std::optional for streaming input

From: Jonathan Wakely <cxx_at_[hidden]>
Date: Sun, 25 Jun 2023 11:19:39 +0100

On Sun, 25 Jun 2023, 02:44 Kevin Schmidt via Std-Proposals, <
std-proposals_at_[hidden]> wrote:

> Thanks for your feedback, they are certainly valid concerns I may have not
> fully thought out. You definitely mentioned some cracking points. I'll
> explain my thoughts further:
> On 6/25/23 01:21, Jonathan Wakely via Std-Proposals wrote:
>> I think the proposal should explain/discuss why that is better than:
>> if (opt)
>> is >> *opt;
>> else {
>> T val;
>> if (is >> val)
>> opt.emplace(val);
>> }
>> i.e. why should it change the state of the optional if reading from the
>> stream fails? Why should it always emplace a new object even if the
>> optional already contains a value?
> I think we should always emplace() a new object and one argument is that
> it's in line with the semantics of streaming operators. When you read into
> a variable using an istream, you generally expect the old value to be
> replaced, not modified.

Do you? What does it mean for an int or std::string to be replaced rather
than modified? To me that would imply destroying the object and recreating
a new one in its memory. That's not what reading into a std::string does,
but it's what using optional::emplace would do.

In concrete terms, this reuses the memory of the string (if it doesn't
need more than 100 bytes) it doesn't replace it:

std::string str;
std::cin >> str;

Maybe your suggestion makes sense for optional, my point is that you need
to give justification for it.

This would hold for std::optional as well, I would say. Concerning the
> resetting of the optional if reading from the stream fails, the rationale
> is to clearly indicate that no valid data was loaded into the optional. The
> absence of a value can be a meaningful signal in this case,

The stream state is set to failbit, that gives you the signal.

Most standard operator>> overloads avoid altering the object on error.

but I do agree that there could certainly be use cases where the
> preservation of the existing value (if any) could be preferred, although I
> would expect to receive the new value in the optional, or receive
> nullopt, indicating an error occurred.
> How?
> Well this would be dependent on the standard implementation. I just wanted
> to highlight the possibility to avoid the unnecessary allocation of the
> stack object "T value", that I mentioned. The managed value could be
> directly set, instead of emplaced and then implicitly set, both are valid
> approaches.
> Unless I'm mistaken, you can't stream into a variant. You can only stream
>> into an already active alternative. Which is similar to optional, where you
>> can only stream into a contained value (not into a disengaged optional).
> You are correct, my mistake, I checked it again on cppreference. Must've
> mixed something up. Currently, std::variant does not have a streaming
> operator defined. I made a wrong comparison. The aim, however, is to make
> std::optional as flexible and intuitive as possible to work with.
> What other stream types do you mean?
> For the reference to other stream types, I was considering the idea of
> serialization and deserialization in other formats, like binary. Though
> overloads for std::istream are most relevant and other 'stream types' might
> have been an overstatement. Excuse me there.

There are no other stream types in the standard library, so I don't think
it's useful to discuss them in this proposal.


Received on 2023-06-25 10:19:56