// { dg-do compile { target c++11 } } // LWG 3545. std::pointer_traits should be SFINAE-friendly #include using std::is_same; template using void_t = void; template class Probe, typename T, typename = void> struct has_member : std::false_type { }; template class Probe, typename T> struct has_member>> : std::true_type { }; template using element_type = typename T::element_type; template using pointer = typename T::pointer; template using difference_type = typename T::difference_type; template using rebind = typename T::template rebind; template using pointer_to = decltype(T::pointer_to(std::declval&>())); using invalid = std::pointer_traits; invalid i; // invalid instantiation is not ill-formed static_assert( !has_member::value, "" ); static_assert( !has_member::value, "" ); static_assert( !has_member::value, "" ); static_assert( !has_member::value, "" ); static_assert( !has_member::value, "" ); struct I { // These members should not be used by pointer_traits

::pointer. using pointer = int; using difference_type = int; template using rebind = int; }; using invalid2 = std::pointer_traits; static_assert( !has_member::value, "" ); static_assert( !has_member::value, "" ); static_assert( !has_member::value, "" ); static_assert( !has_member::value, "" ); static_assert( !has_member::value, "" ); struct P { using element_type = long; struct pointer { }; // should not be used by pointer_traits

::pointer P pointer_to(long&) const; // not static, should not be used. }; using Ptraits = std::pointer_traits

; Ptraits p; static_assert( is_same, long>::value, "" ); static_assert( is_same, P>::value, "" ); static_assert( is_same, std::ptrdiff_t>::value, "" ); static_assert( !has_member::value, "" ); #if __cplusplus >= 202002L // pointer_traits

::pointer_to(long&) is constrained in C++20 and later. static_assert( !has_member::value, "" ); #else static_assert( is_same, P>::value, "" ); #endif struct V { using element_type = const void; }; using Vtraits = std::pointer_traits; Vtraits v; static_assert( is_same, const void>::value, "" ); static_assert( is_same, V>::value, "" ); static_assert( is_same, std::ptrdiff_t>::value, "" ); static_assert( !has_member::value, "" ); static_assert( !has_member::value, "" ); template struct clever_ptr { static T obj; static clever_ptr pointer_to(T&) { return {}; } constexpr T* operator->() const { return &obj; } }; using Ctraits = std::pointer_traits>; static_assert( is_same, char>::value, "" ); static_assert( is_same, clever_ptr>::value, "" ); static_assert( is_same, std::ptrdiff_t>::value, "" ); static_assert( is_same, clever_ptr>::value, "" ); static_assert( is_same, clever_ptr>::value, "" ); #ifdef __cpp_concepts struct ptr_base { }; // Program-defined specialization must not be ambiguous with primary template. template requires std::derived_from struct std::pointer_traits

{ using element_type = int; using difference_type = long; using pointer = P; }; struct Ptr : ptr_base { using element_type = int; }; using E = std::pointer_traits::element_type; #endif