blob: 93c64a353bde7dedb4a4a27cc5e3371027c6cb82 [file] [log] [blame]
// { dg-do compile { target c++11 } }
// LWG 3545. std::pointer_traits should be SFINAE-friendly
#include <memory>
using std::is_same;
template<typename> using void_t = void;
template<template<typename> class Probe, typename T, typename = void>
struct has_member
: std::false_type { };
template<template<typename> class Probe, typename T>
struct has_member<Probe, T, void_t<Probe<T>>>
: std::true_type { };
template<typename T>
using element_type = typename T::element_type;
template<typename T>
using pointer = typename T::pointer;
template<typename T>
using difference_type = typename T::difference_type;
template<typename T>
using rebind = typename T::template rebind<short>;
template<typename T>
using pointer_to = decltype(T::pointer_to(std::declval<element_type<T>&>()));
using invalid = std::pointer_traits<int>;
invalid i; // invalid instantiation is not ill-formed
static_assert( !has_member<element_type, invalid>::value, "" );
static_assert( !has_member<pointer, invalid>::value, "" );
static_assert( !has_member<difference_type, invalid>::value, "" );
static_assert( !has_member<rebind, invalid>::value, "" );
static_assert( !has_member<pointer_to, invalid>::value, "" );
struct I
{
// These members should not be used by pointer_traits<P>::pointer.
using pointer = int;
using difference_type = int;
template<typename> using rebind = int;
};
using invalid2 = std::pointer_traits<I>;
static_assert( !has_member<element_type, invalid2>::value, "" );
static_assert( !has_member<pointer, invalid2>::value, "" );
static_assert( !has_member<difference_type, invalid2>::value, "" );
static_assert( !has_member<rebind, invalid2>::value, "" );
static_assert( !has_member<pointer_to, invalid2>::value, "" );
struct P
{
using element_type = long;
struct pointer { }; // should not be used by pointer_traits<P>::pointer
P pointer_to(long&) const; // not static, should not be used.
};
using Ptraits = std::pointer_traits<P>;
Ptraits p;
static_assert( is_same<element_type<Ptraits>, long>::value, "" );
static_assert( is_same<pointer<Ptraits>, P>::value, "" );
static_assert( is_same<difference_type<Ptraits>, std::ptrdiff_t>::value, "" );
static_assert( !has_member<rebind, Ptraits>::value, "" );
#if __cplusplus >= 202002L
// pointer_traits<P>::pointer_to(long&) is constrained in C++20 and later.
static_assert( !has_member<pointer_to, Ptraits>::value, "" );
#else
static_assert( is_same<pointer_to<Ptraits>, P>::value, "" );
#endif
struct V { using element_type = const void; };
using Vtraits = std::pointer_traits<V>;
Vtraits v;
static_assert( is_same<element_type<Vtraits>, const void>::value, "" );
static_assert( is_same<pointer<Vtraits>, V>::value, "" );
static_assert( is_same<difference_type<Vtraits>, std::ptrdiff_t>::value, "" );
static_assert( !has_member<rebind, Vtraits>::value, "" );
static_assert( !has_member<pointer_to, Vtraits>::value, "" );
template<typename T>
struct clever_ptr
{
static T obj;
static clever_ptr pointer_to(T&) { return {}; }
constexpr T* operator->() const { return &obj; }
};
using Ctraits = std::pointer_traits<clever_ptr<char>>;
static_assert( is_same<element_type<Ctraits>, char>::value, "" );
static_assert( is_same<pointer<Ctraits>, clever_ptr<char>>::value, "" );
static_assert( is_same<difference_type<Ctraits>, std::ptrdiff_t>::value, "" );
static_assert( is_same<rebind<Ctraits>, clever_ptr<short>>::value, "" );
static_assert( is_same<pointer_to<Ctraits>, clever_ptr<char>>::value, "" );
#ifdef __cpp_concepts
struct ptr_base { };
// Program-defined specialization must not be ambiguous with primary template.
template<typename P> requires std::derived_from<P, ptr_base>
struct std::pointer_traits<P>
{
using element_type = int;
using difference_type = long;
using pointer = P;
};
struct Ptr : ptr_base { using element_type = int; };
using E = std::pointer_traits<Ptr>::element_type;
#endif