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@kayari.org>:


On Sat, 24 Jun 2023, 23:38 Kevin Schmidt via Std-Proposals, <std-proposals@lists.isocpp.org> 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@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals