This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of WP status.

### 3632. `unique_ptr` "Mandates: This constructor is not selected by class template argument deduction"

Section: 20.11.1.3.2 [unique.ptr.single.ctor] Status: WP Submitter: Arthur O'Dwyer Opened: 2021-11-03 Last modified: 2022-02-10

Priority: Not Prioritized

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

View all issues with WP status.

Discussion:

P1460R1 changed the wording for `unique_ptr`'s constructor `unique_ptr(pointer)`. In C++17, it said in [unique.ptr.single.ctor] p5:

>     explicit unique_ptr(pointer p) noexcept;

> > Preconditions: […]

> > Effects: […]

> > Postconditions: […]

> > Remarks: If `is_pointer_v<deleter_type>` is `true` or `is_default_constructible_v<deleter_type>` is `false`, this constructor shall not participate in overload resolution. If class template argument deduction would select the function template corresponding to this constructor, then the program is ill-formed.

In C++20, it says in [unique.ptr.single.ctor] p5:

>     explicit unique_ptr(pointer p) noexcept;

> > Constraints: `is_pointer_v<deleter_type>` is `false` and `is_default_constructible_v<deleter_type>` is `true`.

> > Mandates: This constructor is not selected by class template argument deduction.

> > Preconditions: […]

> > Effects: […]

> > Postconditions: […]

Normally, we use "Mandates:" for `static_assert`-like stuff, not just to indicate that some constructor doesn't contribute to CTAD. Both libstdc++ and Microsoft (and soon libc++, see LLVM issue) seem to agree about the intent of this wording: It's basically asking for the constructor to be implemented with a CTAD firewall, as

>     explicit unique_ptr(type_identity_t<pointer> p) noexcept;

and there is no actual `static_assert` corresponding to this "Mandates:" element. In particular, the following program is well-formed on all vendors:

>     // godbolt link
>     template<class T> auto f(T p) -> decltype(std::unique_ptr(p));
>     template<class T> constexpr bool f(T p) { return true; }
>     static_assert(f((int*)nullptr));

I claim that this is a confusing and/or wrong use of "Mandates:". My proposed resolution is simply to respecify the constructor as

>     explicit unique_ptr(type_identity_t<pointer> p) noexcept;

> > Constraints: `is_pointer_v<deleter_type>` is `false` and `is_default_constructible_v<deleter_type>` is `true`.

> > Preconditions: […]

> > Effects: […]

> > Postconditions: […]

with no Mandates: or Remarks: elements at all.

[2022-01-29; Reflector poll]

Set status to Tentatively Ready after five votes in favour during reflector poll.

[2022-02-10 Approved at February 2022 virtual plenary. Status changed: Tentatively Ready → WP.]

Proposed resolution:

This wording is relative to N4901.

1. Modify 20.11.1.3.1 [unique.ptr.single.general], class template `unique_ptr` synopsis, as indicated:

   >     […]
   >     // 20.11.1.3.2 [unique.ptr.single.ctor], constructors
   >     constexpr unique_ptr() noexcept;
   >     explicit unique_ptr(type_identity_t<pointer> p) noexcept;
   >     unique_ptr(type_identity_t<pointer> p, see below d1) noexcept;
   >     unique_ptr(type_identity_t<pointer> p, see below d2) noexcept;
   >     […]

2. Modify 20.11.1.3.2 [unique.ptr.single.ctor] as indicated:

   >     explicit unique_ptr(type_identity_t<pointer> p) noexcept;

   > > -5- Constraints: `is_pointer_v<deleter_type>` is `false` and `is_default_constructible_v<deleter_type>` is `true`.

   > > -6- Mandates: This constructor is not selected by class template argument deduction (12.2.2.9 [over.match.class.deduct]).

   > > -7- Preconditions: […]

   > > -8- Effects: […]

   > > -9- Postconditions: […]

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

   > > -10- Constraints: `is_constructible_v<D, decltype(d)>` is `true`.

   > > -11- Mandates: These constructors are not selected by class template argument deduction (12.2.2.9 [over.match.class.deduct]).

   > > -12- Preconditions: […]

   > > -13- Effects: […]

   > > -14- Postconditions: […]

   > > -15- Remarks: If `D` is a reference type, the second constructor is defined as deleted.

   > > -16- [Example 1: […] — end example]