2228. Missing SFINAE rule in unique_ptr templated assignment

Section: 23.11.1.2.3 [unique.ptr.single.asgn] Status: Resolved Submitter: Geoffrey Romer Opened: 2012-12-20 Last modified: 2016-02-10

Priority: 3

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

View all issues with Resolved status.

Discussion:

23.11.1.2.3 [unique.ptr.single.asgn]/5 permits unique_ptr's templated assignment operator to participate in overload resolution even when incompatibilities between D and E will render the result ill-formed, but the corresponding templated copy constructor is removed from the overload set in those situations (see the third bullet point of 23.11.1.2.1 [unique.ptr.single.ctor]/19). This asymmetry is confusing, and presumably unintended; it may lead to situations where constructing one unique_ptr from another is well-formed, but assigning from the same unique_ptr would be ill-formed.

There is a slight coupling between this and LWG 2118, in that my PR for LWG 2118 incorporates equivalent wording in the specification of the templated assignment operator for the array specialization; the two PRs are logically independent, but if my PR for 2118 is accepted but the above PR is not, the discrepancy between the base template and the specialization could be confusing.

Previous resolution [SUPERSEDED]:

This wording is relative to N3485.

  1. Revise 23.11.1.2.3 [unique.ptr.single.asgn] p5 as follows:

    template <class U, class E> unique_ptr& operator=(unique_ptr<U, E>&& u) noexcept;
    

    -4- Requires: If E is not a reference type, assignment of the deleter from an rvalue of type E shall be well-formed and shall not throw an exception. Otherwise, E is a reference type and assignment of the deleter from an lvalue of type E shall be well-formed and shall not throw an exception.

    -5- Remarks: This operator shall not participate in overload resolution unless:

    • unique_ptr<U, E>::pointer is implicitly convertible to pointer and

    • U is not an array type., and

    • either D is a reference type and E is the same type as D, or D is not a reference type and E is implicitly convertible to D.

    -6- Effects: Transfers ownership from u to *this as if by calling reset(u.release()) followed by an assignment from std::forward<E>(u.get_deleter()).

    -7- Returns: *this.

[2013-03-15 Issues Teleconference]

Moved to Review.

The wording looks good, but we want a little more time than the telecon permits to be truly comfortable. We expect this issue to resolve fairly easily in Bristol.

[2015-05-18, Howard comments]

Updated proposed wording has been provided in N4366.

[2015-05, Lenexa]

Straw poll: send N4366 to full committee, with both fixes from the sections "What is the correct fix?" and "unique_ptr<T[]> needs the correct fix too"

Proposed resolution:

Resolved by accepting N4366.