
Fernando Cacciola wrote:
Sam Partington wrote:
In the rationale the first example states "If you assign to an uninitialized optional<T&> the effect is to bind (for the first time) to the object. Clearly, there is no other choice".
[...]
Remove the operator=(const T&)
int i = 0; optional< int & > o(i); int n = 0; *o = i; // assigns new value o = optional<int&>(i); // rebinds, nice and explicitly
The problem which was raised is that it adds an unnecesary verbosity. That is, why can't you define:
o = val ;
as a convenient shortcut for:
o = optional<T>(val);
All by itself, is looks quite reasonable.
Now you brought this issue back but into the context of optional references.
Is it totally clear to everyone that this rebinds?
o = optional<int&>(i);
Joel de Guzman said that he wouldn't be against rebinding in this case. He's against rebinding in the direct-assignment case, so simply dropping direct-assignment is definitely a way out, even at the cost of dropping some sugar. One could say: optional does not support a convenient direct assignment operator becasue it could hide the true semantics of the assignment, which are clear if only assignment from another optional is used. (Followed by an example)
Why not use partial specialization so that optional< T > has the semantic sugar, but optional< T & > does not? Or is this already the case?
A related note about the use of operator *
You said that, even for optional<T&>, it is clear that this:
*o = i;
is UB if 'o' is uninitialized. And so there is no problem defining that assignment as really just the assignment of the underlying type, which in the case of optional<T&> doesn't rebind.
Now I wonder, if instead of operator*, we used value() (or whatever), would it be just as clear?
// Nullable interface
*o = rb ; // assing 'b' to 'a' o = none ; // releases 'a' *o = rc ; // !!! UB !!! Cleary IMO
// Container interface
o.value() = rb ; // assing 'b' to 'a' o.reset() ; // releases 'a' o.value() = rc ; // !!! Still UB !!! ¿But cleary enough?
I personally prefer the nullable interface as it is more intuitive w.r.t. smart pointer usage. o.value() = b reads to me like value() is returning a (temporary) return value, then you are assigning rb to that. Q: If o == none, does *o = foo throw? (I am not familiar with optional<>) On the optional<bool> side, is it posible to provide a specialization for it that doesn't break the optional interface, but still provides the functionality that is wanted from an optional<bool> type as discussed elsewhere? - Reece