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

### 3233. Broken requirements for `shared_ptr` converting constructors

Section: 20.3.2.2.2 [util.smartptr.shared.const] Status: C++20 Submitter: Casey Carter Opened: 2019-07-10 Last modified: 2021-02-25

Priority: 0

View all other issues in [util.smartptr.shared.const].

View all issues with C++20 status.

Discussion:

Issue 2875 added 20.3.2.2.2 [util.smartptr.shared.const] paragraph 13:

> Remarks: When `T` is an array type, this constructor shall not participate in overload resolution unless `is_move_constructible_v<D>` is `true`, the expression `d(p)` is well-formed, and either `T` is `U[N]` and `Y(*)[N]` is convertible to `T*`, or `T` is `U[]` and `Y(*)[]` is convertible to `T*`. When `T` is not an array type, this constructor shall not participate in overload resolution unless `is_move_constructible_v<D>` is `true`, the expression `d(p)` is well-formed, and `Y*` is convertible to `T*`.

which pertains to the four constructor overloads:

>     template<class Y, class D> shared_ptr(Y* p, D d);
>     template<class Y, class D, class A> shared_ptr(Y* p, D d, A a);
>     template<class D> shared_ptr(nullptr_t p, D d);
>     template<class D, class A> shared_ptr(nullptr_t p, D d, A a);

which is fine (ignoring for now that two occurrences of "this constructor" should read "these constructors") for the two overloads with a template parameter `Y`, but not so much for the two with no such template parameter.

MSVC ignores the constraints on `Y` for the overloads with no such template parameter, whereas libstdc++ and libc++ seem to ignore all of the constraints for those overloads (See Compiler Explorer). We should fix the broken wording, ideally by requiring the MSVC interpretation - the `nullptr_t` constructors participate in overload resolution only when `is_movable_v<D>` is `true` and `d(p)` is well-formed - so concepts and traits that check constructibility are correct.

[2019-11-17 Issue Prioritization]

Status to Tentatively Ready and priority to 0 after six positive votes on the reflector.

Proposed resolution:

This wording is relative to N4835.

1. Modify 20.3.2.2.2 [util.smartptr.shared.const] as indicated:

   > >     template<class Y, class D> shared_ptr(Y* p, D d);
   > >     template<class Y, class D, class A> shared_ptr(Y* p, D d, A a);
   > >     template<class D> shared_ptr(nullptr_t p, D d);
   > >     template<class D, class A> shared_ptr(nullptr_t p, D d, A a);

   > -?- Constraints: `is_move_constructible_v<D>` is `true`, and `d(p)` is a well-formed expression. For the first two overloads:

   > - If `T` is an array type, then either `T` is `U[N]` and `Y(*)[N]` is convertible to `T*`, or `T` is `U[]` and `Y(*)[]` is convertible to `T*`.

   > - If `T` is not an array type, then `Y*` is convertible to `T*`.

   > -9- Requires Expects: Construction of `d` and a deleter of type […]

   > […]

   > -13- Remarks: When `T` is an array type, this constructor shall not participate in overload resolution unless `is_move_constructible_v<D>` is `true`, the expression `d(p)` is well-formed, and either `T` is `U[N]` and `Y(*)[N]` is convertible to `T*`, or `T` is `U[]` and `Y(*)[]` is convertible to `T*`. When `T` is not an array type, this constructor shall not participate in overload resolution unless `is_move_constructible_v<D>` is `true`, the expression `d(p)` is well-formed, and `Y*` is convertible to `T*`.