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.

### 3545. `std::pointer_traits` should be SFINAE-friendly

Section: 20.2.3 [pointer.traits] Status: WP Submitter: Glen Joseph Fernandes Opened: 2021-04-20 Last modified: 2022-11-17

Priority: 2

View all other issues in [pointer.traits].

View all issues with WP status.

Discussion:

P1474R1 chose to use `std::to_address` (a mechanism of converting pointer-like types to raw pointers) for contiguous iterators. `std::to_address` provides an optional customization point via an optional member in `std::pointer_traits`. However all iterators are not pointers, and the primary template of `std::pointer_traits<Ptr>` requires that either `Ptr::element_type` is valid or `Ptr` is of the form `template<T, Args...>` or the `pointer_traits` specialization is ill-formed. This requires specializing `pointer_traits` for those contiguous iterator types which is inconvenient for users. P1474 should have also made `pointer_traits` SFINAE friendly.

[2021-05-10; Reflector poll]

Priority set to 2. Send to LEWG. Daniel: "there is no similar treatment for the `rebind` member template and I think it should be clarified whether `pointer_to`'s signature should exist and in which form in the offending case."

[2022-01-29; Daniel comments]

This issue has some overlap with LWG 3665 in regard to the question how we should handle the `rebind_alloc` member template of the `allocator_traits` template as specified by 20.2.9.2 [allocator.traits.types]/11. It would seem preferable to decide for the same approach in both cases.

[2022-02-22 LEWG telecon; Status changed: LEWG → Open]

No objection to unanimous consent for Jonathan's suggestion to make `pointer_traits` an empty class when there is no `element_type`. Jonathan to provide a paper.

Previous resolution [SUPERSEDED]:

> This wording is relative to N4885.

> 1. Modify 20.2.3.2 [pointer.traits.types] as indicated:

>    > As additional drive-by fix the improper usage of the term "instantiation" has been corrected.

>    >     using element_type = see below;

>    > > -1- Type: `Ptr::element_type` if the qualified-id `Ptr::element_type` is valid and denotes a type (13.10.3 [temp.deduct]); otherwise, `T` if `Ptr` is a class template instantiation specialization of the form `SomePointer<T, Args>`, where `Args` is zero or more type arguments; otherwise, the specialization is ill-formed `pointer_traits` has no member `element_type`.

[2022-09-27; Jonathan provides new wording]

Previous resolution [SUPERSEDED]:

> This wording is relative to N4917.

> 1. Modify 20.2.3.1 [pointer.traits.general] as indicated:

>    > -1- The class template `pointer_traits` supplies a uniform interface to certain attributes of pointer-like types.

>    > >     namespace std {
>    > >       template<class Ptr> struct pointer_traits {
>    > >         using pointer         = Ptr;
>    > >         using element_type    = see below;
>    > >         using difference_type = see below;

>    > >         template<class U> using rebind = see below;
>    > >         static pointer pointer_to(see below r);

>    > >         see below;
>    > >       };

>    > >       template<class T> struct pointer_traits<T*> {
>    > >         using pointer         = T*;
>    > >         using element_type    = T;
>    > >         using difference_type = ptrdiff_t;

>    > >         template<class U> using rebind = U*;
>    > >         static constexpr pointer pointer_to(see below r) noexcept;
>    > >       };
>    > >     }

> 2. Modify 20.2.3.2 [pointer.traits.types] as indicated:

>    > -?- The definitions in this subclause make use of the following exposition-only class template and concept:

>    > >     template<class T>
>    > >     struct ptr-traits-elem // exposition only
>    > >     { };

>    > >     template<class T> requires requires { typename T::element_type; }
>    > >     struct ptr-traits-elem<T>
>    > >     { using type = typename T::element_type; };

>    > >     template<template<class...> class SomePointer, class T, class... Args>
>    > >     requires (!requires { typename SomePointer<T, Args...>::element_type; })
>    > >     struct ptr-traits-elem<SomePointer<T, Args...>>
>    > >     { using type = T; };

>    > >     template<class Ptr>
>    > >       concept has-elem-type = // exposition only
>    > >         requires { typename ptr-traits-elem<Ptr>::type; }

>    > -?- If `Ptr` satisfies `has-elem-type`, a specialization `pointer_traits<Ptr>` generated from the `pointer_traits` primary template has the members described in 20.2.3.2 [pointer.traits.types] and 20.2.3.3 [pointer.traits.functions]; otherwise, such a specialization has no members by any of the names described in those subclauses or in 20.2.3.4 [pointer.traits.optmem].

>    >     using pointer = Ptr;

>    >     using element_type = see below typename ptr-traits-elem<Ptr>::type;

>    > > -1- Type: `Ptr::element_type` if the qualified-id `Ptr::element_type` is valid and denotes a type (13.10.3 [temp.deduct]); otherwise, `T` if `Ptr` is a class template instantiation of the form `SomePointer<T, Args>`, where `Args` is zero or more type arguments; otherwise, the specialization is ill-formed.

>    >     using difference_type = see below;

>    > > -2- Type: `Ptr::difference_type` if the qualified-id `Ptr::difference_type` is valid and denotes a type (13.10.3 [temp.deduct]); otherwise, `ptrdiff_t`.

>    >     template<class U> using rebind = see below;

>    > > -3- Alias template: `Ptr::rebind<U>` if the qualified-id `Ptr::rebind<U>` is valid and denotes a type (13.10.3 [temp.deduct]); otherwise, `SomePointer<U, Args>` if `Ptr` is a class template instantiation of the form `SomePointer<T, Args>`, where `Args` is zero or more type arguments; otherwise, the instantiation of `rebind` is ill-formed.

[2022-10-11; Jonathan provides improved wording]

[2022-10-19; Reflector poll]

Set status to "Tentatively Ready" after six votes in favour in reflector poll.

[2022-11-12 Approved at November 2022 meeting in Kona. Status changed: Voting → WP.]

Proposed resolution:

This wording is relative to N4917.

1. Modify 20.2.3.1 [pointer.traits.general] as indicated:

   > -1- The class template `pointer_traits` supplies a uniform interface to certain attributes of pointer-like types.

   > >     namespace std {
   > >       template<class Ptr> struct pointer_traits {
   > >         using pointer         = Ptr;
   > >         using element_type    = see below;
   > >         using difference_type = see below;

   > >         template<class U> using rebind = see below;
   > >         static pointer pointer_to(see below r);

   > >         see below;
   > >       };

   > >       template<class T> struct pointer_traits<T*> {
   > >         using pointer         = T*;
   > >         using element_type    = T;
   > >         using difference_type = ptrdiff_t;

   > >         template<class U> using rebind = U*;
   > >         static constexpr pointer pointer_to(see below r) noexcept;
   > >       };
   > >     }

2. Modify 20.2.3.2 [pointer.traits.types] as indicated:

   > -?- The definitions in this subclause make use of the following exposition-only class template and concept:

   > >     template<class T>
   > >     struct ptr-traits-elem // exposition only
   > >     { };

   > >     template<class T> requires requires { typename T::element_type; }
   > >     struct ptr-traits-elem<T>
   > >     { using type = typename T::element_type; };

   > >     template<template<class...> class SomePointer, class T, class... Args>
   > >     requires (!requires { typename SomePointer<T, Args...>::element_type; })
   > >     struct ptr-traits-elem<SomePointer<T, Args...>>
   > >     { using type = T; };

   > >     template<class Ptr>
   > >       concept has-elem-type = // exposition only
   > >         requires { typename ptr-traits-elem<Ptr>::type; }

   > -?- If `Ptr` satisfies `has-elem-type`, a specialization `pointer_traits<Ptr>` generated from the `pointer_traits` primary template has the following members as well as those described in 20.2.3.3 [pointer.traits.functions]; otherwise, such a specialization has no members by any of those names.

   >     using pointer = see below;

   > > -?- Type: `Ptr`.

   >     using element_type = see below;

   > > -1- Type: `typename ptr-traits-elem<Ptr>::type`. `Ptr::element_type` if the qualified-id `Ptr::element_type` is valid and denotes a type (13.10.3 [temp.deduct]); otherwise, `T` if `Ptr` is a class template instantiation of the form `SomePointer<T, Args>`, where `Args` is zero or more type arguments; otherwise, the specialization is ill-formed.

   >     using difference_type = see below;

   > > -2- Type: `Ptr::difference_type` if the qualified-id `Ptr::difference_type` is valid and denotes a type (13.10.3 [temp.deduct]); otherwise, `ptrdiff_t`.

   >     template<class U> using rebind = see below;

   > > -3- Alias template: `Ptr::rebind<U>` if the qualified-id `Ptr::rebind<U>` is valid and denotes a type (13.10.3 [temp.deduct]); otherwise, `SomePointer<U, Args>` if `Ptr` is a class template instantiation of the form `SomePointer<T, Args>`, where `Args` is zero or more type arguments; otherwise, the instantiation of `rebind` is ill-formed.

3. Modify 20.2.3.4 [pointer.traits.optmem] as indicated:

   > -1- Specializations of `pointer_traits` may define the member declared in this subclause to customize the behavior of the standard library. A specialization generated from the `pointer_traits` primary template has no member by this name.

   >     static element_type* to_address(pointer p) noexcept;

   > > -1- Returns: A pointer of type `element_type*` that references the same location as the argument `p`.