7
\$\begingroup\$

pointer_traits is a lightweight trait that provides a uniform interface to builtin pointers and user-defined fancy pointers. That said, things like element_type require template metaprogramming techniques to determine. This makes pointer_traits a good exercise.

Here's my re-implementation under the name my_std::pointer_traits, put in a separate header pointer_traits.hpp because <memory> is way too comprehensive:

// C++17 pointer_traits implementation

#ifndef INC_POINTER_TRAITS_HPP_60HzB0lbek
#define INC_POINTER_TRAITS_HPP_60HzB0lbek

#include <cstddef>     // for std::ptrdiff_t
#include <memory>      // for std::addressof
#include <type_traits> // for std::add_lvalue_reference

namespace my_std {

  template <class Ptr>
  struct pointer_traits;

  namespace pt_detail {

    template <class Tmpl>
    struct get_first_param { };
    template <template <class, class...> class Tmpl, class T, class... Args>
    struct get_first_param<Tmpl<T, Args...>> {
      using type = T;
    };
    template <class Tmpl>
    using get_first_param_t = typename get_first_param<Tmpl>::type;

    template <class Tmpl, class U>
    struct rebind_first_param { };
    template <template <class, class...> class Tmpl, class T, class... Args, class U>
    struct rebind_first_param<Tmpl<T, Args...>, U> {
      using type = Tmpl<U, Args...>;
    };
    template <class Tmpl, class U>
    using rebind_first_param_t = typename rebind_first_param<Tmpl, U>::type;

    template <class Ptr>
    auto element(int) -> typename Ptr::element_type;
    template <class Ptr>
    auto element(long) -> get_first_param_t<Ptr>;

    template <class Ptr>
    auto diff(int) -> typename Ptr::difference_type;
    template <class Ptr>
    auto diff(long) -> std::ptrdiff_t;

    template <class Ptr, class U>
    auto rebind(int) -> typename Ptr::template rebind<U>;
    template <class Ptr, class U>
    auto rebind(long) -> rebind_first_param_t<Ptr, U>;

  }

  template <class Ptr>
  struct pointer_traits {
    using pointer = Ptr;
    using element_type = decltype(pt_detail::element<Ptr>(0));
    using difference_type = decltype(pt_detail::diff<Ptr>(0));

    template <class U>
    using rebind = decltype(pt_detail::rebind<Ptr, U>(0));

    static pointer pointer_to(std::add_lvalue_reference<element_type> r)
    {
      return Ptr::pointer_to(r);
    }
  };

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

    template <class U>
    using rebind = U*;

    static pointer pointer_to(std::add_lvalue_reference<element_type> r)
    {
      return std::addressof(r);
    }
  };

}

#endif

I used N4659 as a reference.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.