Why std::optional
(std::experimental::optional
in libc++ at the moment) does not have specialization for reference types (compared
The main problem with std::optional <T&>
is — what should optRef = obj
do in the following case:
optional<T&> optRef;
…;
T obj {…};
optRef = obj; // <-- here!
Variants:
(&optRef)->~optional(); new (&optRef) optional<T&>(obj)
.*optRef = obj
(UB when !optRef
before).if (optRef) {do1;} else {do2;}
.Pros of every variant:
Always rebind (chosen by boost::optional and n1878):
!optRef
and optRef.has_value()
— post-condition &*optRef == &obj
is always met.optional<T>
in the following aspect: for usual optional<T>
, if T::operator=
is defined to act as destroying and constructing (and some argue that it must be nothing more than optimization for destroying-and-constructing), opt = …
de facto acts similarly like (&opt)->~optional(); new (&opt) optional<T&>(obj)
.Assign through:
T&
in the following aspect: for pure T&
, ref = …
assigns through (not rebinds the ref
).optional<T>
in the following aspect: for usual optional<T>
, when opt.has_value()
, opt = …
is required to assign through, not to destroy-and-construct (see template <class U> optional<T>& optional<T>::operator=(U&& v)
in n3672 and on cppreference.com).optional<T>
in the following aspect: both haveoperator=
defined at least somehow.Bind if empty, assign through otherwise — I see no real benefits, IMHO this variant arises only when proponents of #1 argue with proponents of #2, however formally it's even more consistent with the letter of requirements for template <class U> optional<T>& optional<T>::operator=(U&& v)
(but not with the spirit, IMHO).
No assignment operator (chosen by n3406):
T&
in the following aspect: pure T&
doesn't allow to rebind itself.See also:
There is indeed something that has reference to maybe existing object semantics. It is called a (const) pointer. A plain old non-owning pointer. There are three differences between references and pointers:
std::optional
.->
or *
. This is pure syntactic sugar and possible because of 1. And the pointer syntax (dereferencing and convertible to bool) is exactly what std::optional
provides for accessing the value and testing its presence.Update:
optional
is a container for values. Like other containers (vector
, for example) it is not designed to contain references. If you want an optional reference, use a pointer, or if you indeed need an interface with a similar syntax to std::optional
, create a small (and trivial) wrapper for pointers.
Update2: As for the question why there is no such specialization: because the committee simply did opt it out. The rationale might be found somewhere in the papers. It possibly is because they considered pointers to be sufficient.
If I would hazard a guess, it would be because of this sentence in the specification of std::experimental::optional. (Section 5.2, p1)
A program that necessitates the instantiation of template
optional
for a reference type, or for possibly cv-qualified typesin_place_t
ornullopt_t
is ill-formed.
IMHO it is very okay to make std::optional<T&>
available. However there is a subtle issue about templates. Template parameters can become tricky to deal with if there are references.
Just as the way we solved the problem of references in template parameters, we can use a std::reference_wrapper
to circumvent the absence of std::optional<T&>
. So now it becomes std::optional<std::reference_wrapper<T>>
. However I recommend against this use because 1) it is way too verbose to both write the signature (trailing return type saves us a bit) and the use of it (we have to call std::reference_wrapper<T>::get()
to get the real reference), and 2) most programmers have already been tortured by pointers so that it is like an instinctive reaction that when they receive a pointer they test first whether it is null so it is not quite much an issue now.
When n3406 (revision #2 of the proposal) was discussed, some committee members were uncomfortable with optional references. In n3527 (revision #3), the authors decided to make optional references an auxiliary proposal, to increase the chances of getting optional values approved and put into what became C++14. While optional didn't quite make it into C++14 for various other reasons, the committee did not reject optional references and is free to add optional references in the future should someone propose it.