I've followed std::optional closely through the standardization process, so I 
can give some background info:

- from the beginning Boost::optional was written with a pointer-like syntax:

        optional<int> op = maybe_get_the_value();

        if (op) {
                int x = *op;
                ...
        }

The original Boost author felt *strongly* that a pointer-like API would be 
best, as developers are familiar with the paradigm.

- optional's constructor allows *implicit* conversion from T, for various 
reasons, including so that it is easy to change a function that takes a T into 
a function that takes an optional<T>.

// version 1:
int function(int); 
// version 2:
int function(optional<int>);

// my code:
int x = function(17); // works with both versions

- Assuming optional<T> == optional<T> exists, then implicit constructors means 
that things like optional<T> == T automatically work (T is implicitly converted 
to optional<T>)

so optional<bool>(false) == bool(false) can compile.  But that has the 
confusion with if (op).  Which is done as an _explicit_ bool  conversion.

Once you have == and !=, the next question is <,>,<=,>=.  It is easy to say we 
don't want/need these.  HOWEVER...

We want operator<() so that optionals can be placed into ordered containers, be 
sorted, etc.  More precisely, we want std::less to work.  But if std::less 
works, shouldn't operator<() as well (and shouldn't they give the same results!)

...  note that there are some rare cases that std::less works, but operator<() 
doesn't - ie pointers (in general).  Also, sooner or later, probably 
std::complex will be similar.  (Currently std::complex can't be used as a key 
in map, giving it std::less would fix that.  But we don't want complex to have 
operator<() as it doesn't really make sense...)


Overall, optional can be seen in many ways:

1.    Just a T with deferred initialization / lifetime management.
2.    A discriminated union of types nullopt_t and T.
3.    A container of T's with the maximum size of 1.
4.    A type "T+" which is the same as T, but with one more value

The interface of std::experimental::optional is most closely aligned with 1 and 
4.  It definitely doesn't have much container interface (like 
begin/end/iterator/...).

1 is what optional really is, everything else is extending it to try to be more 
than that.
It is really 1 because "op = 17" does construction or assignment depending on 
whether the optional was already engaged or not.  If your class handles 
construction and assignment differently, this is an important distinction. (Of 
course most types are Regular so not an issue.)

Oh, and then there are (or are not) optional<T&> types to consider.  The 
standard is avoiding those for now. (Note that T& is not Regular, and that for 
references construction and assignment of are different!)


And yes, these issues are why it is in a TS instead of C++14.  

Tony

_______________________________________________
Development mailing list
Development@qt-project.org
http://lists.qt-project.org/mailman/listinfo/development

Reply via email to