[ 2012-12-20: Geoffrey Romer comments and provides a revised resolution ]
The array specialization of unique_ptr differs from the primary template in several ways, including the following:
unique_ptr<T[], D> cannot be constructed from a plain pointer whose type is not exactly unique_ptr<T[], D>::pointer or nullptr_t.
unique_ptr<T[], D> cannot be constructed from a unique_ptr<U[], E>&& unless U is exactly T and E is exactly D.
unique_ptr<T[], D> cannot be moveassigned from a unique_ptr<U[], E>&& unless U is exactly T and E is exactly D.
unique_ptr<T[], D>::reset cannot take an argument whose type is not exactly unique_ptr<T[], D>::pointer or nullptr_t.
default_delete<T[]> cannot be constructed from a default_delete<U[]> unless U is exactly T.
default_delete<T[]>::operator() cannot be called on a pointer whose type is not exactly T*.
The common intent of all these restrictions appears to be to disallow implicit conversions from pointer-to-derived-class to pointer-to-base-class in contexts where the pointer is known to point to an array, because such conversions are inherently unsafe; deleting or subscripting the result of such a conversion leads to undefined behavior (see also CWG 1504). However, these restrictions have the effect of disallowing all implicit conversions in those contexts, including most notably cv-qualification, but also user-defined conversions, and possibly others. This PR narrows all those restrictions, to disallow only unsafe pointer-to-derived to pointer-to-base conversions, while allowing all others.
I removed the nebulous language stating that certain functions "will not accept" certain arguments. Instead I use explicitly deleted template functions, which participate in overload resolution only for pointer-to-derived to pointer-to-base conversions. This is more consistent with the existing text and easier to express correctly than an approach based on declaring certain types of calls to be ill-formed, but may produce inferior compiler diagnostics.
Wherever possible, this PR defines the semantics of template specializations in terms of their differences from the primary template. This improves clarity and minimizes the risk of unintended differences (e.g. LWG 2169, which this PR also fixes). This PR also makes it explicit that the specialization inherits the description of all members, not just member functions, from the primary template and, in passing, clarifies the default definition of pointer in the specialization.
This resolution only disallows pointer-to-derived to pointer-to-base conversions between ordinary pointer types; if user-defined pointer types provide comparable conversions, it is their responsibility to ensure they are safe. This is consistent with C++'s general preference for expressive power over safety, and for assuming the user knows what they're doing; furthermore, enforcing such a restriction on user-defined types appears to be impractical without cooperation from the user.
The "base class without regard to cv-qualifiers" language is intended to parallel the specification of std::is_base_of.
Jonathan Wakely has a working implementation of this PR patched into libstdc++.
Previous resolution:
This wording is relative to the FDIS.
Change [unique.ptr.runtime.ctor] as indicated:
explicit unique_ptr(pointer p) noexcept; unique_ptr(pointer p, see below d) noexcept; unique_ptr(pointer p, see below d) noexcept;These constructors behave the same as in the primary template except that
they do not accept pointer types which are convertible to pointerargument pointers p to types derived from T are rejected by the constructors. [Note: One implementation technique is to create private templated overloads of these members. — end note]