Fernando Cacciola said: > From: "Peter Dimov" <[EMAIL PROTECTED]> >> From: "Fernando Cacciola" <[EMAIL PROTECTED]> >> > > optional<T> m(t); >> > > >> > > > foo(m, m); // comparison inside yields false >> >> where foo is >> >> void foo(optional<T> const &, optional<T> const &); >> >> > > > >> > Nop... :-) >> > >> > it compares true because get_pointer(x)==get_poiner(x) is true for >> any > x, >> > whether initialized or not. >> >> True. Had foo been >> >> void foo(optional<T>, optional<T>); >> >> or had the call been >> >> foo(optional<T>(t), optional<T>(t)); // corresponds to foo(&t, &t) >> >> I would have been right. >> > Ouch! Nasty :-) > > OK, deep-copyness breaks pointer-semantic at some point no matter how > much you try to fake it.... > > But then I have to go back to my original decision of disallowing > relational operations directly, because they won't work as I wanted > (with semantics invariant under type change). > > William?
I'm mostly still on the fence. I like the syntactic sugar of being able to compare optionals under the assumption that "uninitialized" is just another possible value. I see this being done a lot, and the currently required verbose "if (opt1 == opt2 && *opt1 == *opt2)" seems to add little clarity and a lot of inconvenience. However, I also understand how this can be viewed as confusing and not really compatible with the pointer semantics present in optional<>. To be honest, I'm wondering if the pointer semantics should just be dropped. Here's the rationale you provide for pointer semantics: * Is easy to test for "uninitialized" state. This is just as easily covered with the safe-bool idiom. * Is "safe" on platforms where dereferencing a pointer results in a non-language exception or a core dump. This is just as easily covered (and can be made well defined on all platforms) by throwing an exception when you call a get() that returns a reference. * Can be dropped in in places where pointers are currently used. I'm not convinced this reason is compelling enough. The only real use case given that carries any weight is changing from an optional<foo> to shared_ptr<foo> if foo grows too complex for efficient copying. But then, why not simply make foo more "copy friendly" through the letter-envelope idiom, or maybe give it move semantics? And if that's not viable, is it that bad to have to deal with refactoring the code in this use case (which I would think would be relatively rare)? I see the appeal of pointer semantics, but the issues being raised make me wonder if the "mixed metaphor" that results is not more trouble than it's worth. I'm thinking that maybe the interface should be as simple as: template <typename T> class optional { public: optional(); explicit optional(T const& value); // Does it need to be explicit? optional(optional const& other); template <typename U> optional(optional<U> const& other); operator safe-bool(); T& ref(); T const& ref() const; }; template <typename T> bool operator==(optional<T> const& opt1, optional<T> const& opt2); template <typename T> bool operator!=(optional<T> const& opt1, optional<T> const& opt2); This appears to be much cleaner, and avoids the design issues we've been struggling with all week. The one wart that may bite users is still the safe-bool leading to possible confusion when T is bool (or convertable to bool), but like I've said before, we already have cases in the language where we have to be vigilant of this, so it doesn't bother me. William E. Kempf _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost