C++ Logo

std-proposals

Advanced search

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

From: Kevin Schmidt <kevin_at_[hidden]>
Date: Sun, 25 Jun 2023 03:43:40 +0200
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. 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, 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.

Am So., 25. Juni 2023 um 01:21 Uhr schrieb Jonathan Wakely <cxx_at_[hidden]>:

>
>
> On Sat, 24 Jun 2023, 23:38 Kevin Schmidt via Std-Proposals, <
> std-proposals_at_[hidden]> wrote:
>
>> Hello everybody, I would like to propose the following for the new
>> standard:
>>
>> Motivation:
>>
>> Currently, std::optional does not have an operator>> defined, so values
>> cannot be streamed directly into an std::optional. Users have to explicitly
>> extract the value from the stream and assign it to the std::optional using
>> emplace() or operator=(). By adding operator>> overloads, std::optional can
>> support more intuitive streaming input.
>>
>> Initial Design Proposition:
>>
>> template <typename T>
>> std::istream& operator>>(std::istream& is, std::optional<T>& opt) {
>> T value;
>> if (is >> value) {
>> opt.emplace(value);
>> } else {
>> opt.reset();
>> }
>> return is;
>> }
>>
>
> 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?
>
>
>
>> This defines an operator>> that extracts a value of type T from the input
>> stream "is" and assigns it to the std::optional<T> object "opt". If the
>> extraction succeeds, the value is emplace()d into "opt". If it fails, "opt"
>> is reset to an empty state. This is just a basic implementation that can be
>> used without the internals. For the implementation into the standard I
>> would suggest a rewrite using the internals of std::optional to overcome
>> the issue of using one unnecessary stack allocation.
>>
>
> How?
>
>
> I still believe that mentioning this is important though since this code
>> can be used as a premature implementation for now.
>>
>> The implementation allows code like:
>>
>> std::optional<int> opt;
>> std::istringstream("123") >> opt;
>> // opt is 123
>>
>> Impact on the Standard:
>>
>> This change will make std::optional more intuitive to use for streaming
>> input, as values can be extracted directly into an optional without needing
>> to handle the empty case explicitly. It brings std::optional inline with
>> other wrapper types like std::variant that support streaming through
>> operator>> overloads.
>>
>
> 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).
>
>
>
>
>
>
>> The proposed changes are limited to overloads for std::istream and its
>> derived types. Overloads for other stream types can be added separately.
>>
>
> What other stream types do you mean?
>
> The proposed design is limited to a single-argument overload to avoid
>> ambiguity, but additional overloads can be defined if needed.
>>
>> This change should have limited impact on existing code, as it purely
>> adds additional functionality. The proposed design has been kept simple,
>> but can be extended in the future if needed.
>>
>> I hope that this fits nicely into the standard, any feedback or
>> improvement suggestions are welcome.
>>
>> Thanks for your attention,
>> Kevin
>> --
>> Std-Proposals mailing list
>> Std-Proposals_at_[hidden]
>> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>>
>

Received on 2023-06-25 01:43:53