3164. Unhelpful "shall not participate" constraints for unique_ptr with reference deleter

Section: 20.3.1.3.2 [unique.ptr.single.ctor] Status: NAD Submitter: Jonathan Wakely Opened: 2018-10-09 Last modified: 2018-11-27

Priority: Not Prioritized

View all other issues in [unique.ptr.single.ctor].

View all issues with NAD status.

Discussion:

[unique.ptr.single.ctor] defines these constructors:

unique_ptr(pointer p, const D& d) noexcept;
unique_ptr(pointer p, remove_reference_t<D>&& d) noexcept;

and p13 says:

Remarks: If D is a reference type, the second constructor is defined as deleted. These constructors shall not participate in overload resolution unless is_constructible_v<D, decltype(d)> is true.

The first sentence in the Remarks has no effect. If D is a reference type A&, then for the second constructor the condition is is_constructible<A&, A&&> which is false. So the second constructor never participates in overload resolution for reference deleters, and so it's irrelevant whether it's deleted or not.

We should either strike that sentence, or adjust the is_constructible constraint so that the deleted constructor participates in overload resolution for deleters of reference type. That way trying to initialize a deleter of reference type from an rvalue will resolve to the deleted function as intended.

I think we can just change the "shall not participate" condition to only apply to non-reference deleters. For reference deleters the condition is always true for the first constructor, because is_constructible<A&, A&> is true, and always false for the second constructor (but we want it to be true so the deleted constructor is used). So for both constructors, the "shall not participate" isn't useful when D is a reference type.

11-2018 Status to NAD after discussion on the reflector.

Proposed resolution:

This wording is relative to N4778.

  1. Change 20.3.1.3.2 [unique.ptr.single.ctor] as indicated:

    unique_ptr(pointer p, const D& d) noexcept;
    unique_ptr(pointer p, remove_reference_t<D>&& d) noexcept;
    

    […]

    -11- Remarks: If D is a reference type, the second constructor is defined as deleted. If D is not a reference type, tThese constructors shall not participate in overload resolution unless is_constructible_v<D, decltype(d)> is true.

    […]