Title
std::pointer_traits should be SFINAE-friendly
Status
c++23
Section
[pointer.traits]
Submitter
Glen Joseph Fernandes

Created on 2021-04-20.00:00:00 last changed 13 months ago

Messages

Date: 2022-11-17.00:42:33

Proposed resolution:

This wording is relative to N4917.

  1. Modify [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 [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 [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 ([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 ([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 ([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 [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.

Date: 2022-11-12.00:00:00

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

Date: 2022-10-15.00:00:00

[ 2022-10-19; Reflector poll ]

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

Date: 2022-10-15.00:00:00

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

Date: 2022-09-15.00:00:00

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

Previous resolution [SUPERSEDED]:

This wording is relative to N4917.

  1. Modify [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 [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 [pointer.traits.types] and [pointer.traits.functions]; otherwise, such a specialization has no members by any of the names described in those subclauses or in [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 ([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 ([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 ([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.

Date: 2022-02-22.00:00:00

[ 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 [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 ([temp.deduct]); otherwise, T if Ptr is a class template instantiationspecialization of the form SomePointer<T, Args>, where Args is zero or more type arguments; otherwise, the specialization is ill-formedpointer_traits has no member element_type.

Date: 2022-01-15.00:00:00

[ 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 [allocator.traits.types]/11. It would seem preferable to decide for the same approach in both cases.

Date: 2021-05-15.00:00:00

[ 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."

Date: 2021-04-20.00:00:00

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.

History
Date User Action Args
2023-11-22 15:47:43adminsetstatus: wp -> c++23
2022-11-17 00:42:33adminsetmessages: + msg13046
2022-11-17 00:42:33adminsetstatus: voting -> wp
2022-11-08 03:46:49adminsetstatus: ready -> voting
2022-10-19 20:27:16adminsetmessages: + msg12877
2022-10-19 20:27:16adminsetstatus: open -> ready
2022-10-12 14:38:10adminsetmessages: + msg12850
2022-09-27 14:59:18adminsetmessages: + msg12821
2022-02-23 11:11:18adminsetmessages: + msg12383
2022-02-23 11:11:18adminsetstatus: lewg -> open
2022-01-29 12:13:52adminsetmessages: + msg12283
2021-11-15 13:29:10adminsetstatus: new -> lewg
2021-05-10 16:30:18adminsetmessages: + msg11798
2021-04-24 17:24:50adminsetmessages: + msg11787
2021-04-20 00:00:00admincreate