std::pointer_traits
should be SFINAE-friendlySection: 20.2.3 [pointer.traits] Status: C++23 Submitter: Glen Joseph Fernandes Opened: 2021-04-20 Last modified: 2023-11-22
Priority: 2
View all other issues in [pointer.traits].
View all issues with C++23 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.
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-idPtr::element_type
is valid and denotes a type (13.10.3 [temp.deduct]); otherwise,T
ifPtr
is a class templateinstantiationspecialization of the formSomePointer<T, Args>
, whereArgs
is zero or more type arguments; otherwise,the specialization is ill-formedpointer_traits
has no memberelement_type
.
[2022-09-27; Jonathan provides new wording]
Previous resolution [SUPERSEDED]:
This wording is relative to N4917.
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; }; }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
satisfieshas-elem-type
, a specializationpointer_traits<Ptr>
generated from thepointer_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 belowtypename ptr-traits-elem<Ptr>::type;
-1- Type:Ptr::element_type
if the qualified-idPtr::element_type
is valid and denotes a type (13.10.3 [temp.deduct]); otherwise,T
ifPtr
is a class template instantiation of the formSomePointer<T, Args>
, whereArgs
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-idPtr::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-idPtr::rebind<U>
is valid and denotes a type (13.10.3 [temp.deduct]); otherwise,SomePointer<U, Args>
ifPtr
is a class template instantiation of the formSomePointer<T, Args>
, whereArgs
is zero or more type arguments; otherwise, the instantiation ofrebind
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.
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; }; }
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
satisfieshas-elem-type
, a specializationpointer_traits<Ptr>
generated from thepointer_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-idPtr::element_type
is valid and denotes a type (13.10.3 [temp.deduct]); otherwise,T
ifPtr
is a class template instantiation of the formSomePointer<T, Args>
, whereArgs
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-idPtr::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-idPtr::rebind<U>
is valid and denotes a type (13.10.3 [temp.deduct]); otherwise,SomePointer<U, Args>
ifPtr
is a class template instantiation of the formSomePointer<T, Args>
, whereArgs
is zero or more type arguments; otherwise, the instantiation ofrebind
is ill-formed.
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 thepointer_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 argumentp
.