It comes down to another ambiguity. One example: if T
can be constructed from optional<T>
, what should happen when an optional<T>
is constructed from an optional<T>
object? Is the desired behavior copy construction of optional<T>
or forwarding of the parameter to the T
constructor?
This was addressed in N3527 (whose link I obtained from an answer to a related question.) The possibility of forwarding arguments was considered, but dismissed.
However, there are also certain problems with this [perfect forwarding] model. First, there are exceptions to perfect forwarding: the tag nullopt
is not forwarded. Also, arguments of type optional<T>
are not. This becomes visible if T has such constructor:
struct MyType
{
MyType(optional<MyType>, int = 0);
// ...
};
Also, in general, it is impossible to perfect-forward initializer_list as the special deduction rules are involved.
The paper also identified a problem with default construction under perfect forwarding. (A default constructed optional<T>
would contain a default-constructed T
instead of not containing a value.) This part could be side-stepped – at the cost of some consistency – by requiring the in_place_t
tag to construct an optional<T>
that contains a default-constructed T
. I view this as the lesser obstacle and the ambiguity issue as the major one.
I suppose you could press on and ask why not forward two or more arguments (when the first one is not the tag)? At some point consistency does become a desirable goal. Keep the interface simple. If a tag is needed for zero or one parameters to be forwarded to the constructor of T
, then require it for any number of parameters. Fewer rules to remember results in fewer programming errors.