shared_ptr.hpp: improve is_same_ptr<> trait

Don't always return true on MSVC.
This commit is contained in:
Nekotekina 2021-04-07 18:52:25 +03:00
parent 02febd3f65
commit 94c62b1eec

View File

@ -6,55 +6,58 @@
namespace stx namespace stx
{ {
#ifndef _MSC_VER namespace detail
#pragma GCC diagnostic push {
#ifdef __clang__ template <typename T>
#pragma GCC diagnostic ignored "-Wundefined-var-template" union fake_t
#pragma GCC diagnostic ignored "-Wundefined-internal" {
#endif char dummy;
#endif T data;
// Not defined anywhere (and produces a useless warning) fake_t() noexcept {}
template <typename X> ~fake_t() {}
extern X sample; };
template <typename T>
static const fake_t<std::remove_cv_t<T>> sample{};
}
template <typename X, typename Y>
constexpr bool is_same_ptr_test(const volatile Y*, ...)
{
// Can't sample abstract class
return false;
}
template <typename X, typename Y, std::enable_if_t<!std::is_abstract_v<Y>, int> = 0>
constexpr bool is_same_ptr_test(const volatile Y* ptr = std::addressof(detail::sample<Y>.data))
{
return static_cast<const volatile X*>(ptr) == static_cast<const volatile void*>(ptr);
}
// Checks whether the cast between two types is the same pointer // Checks whether the cast between two types is the same pointer
template <typename T, typename U> template <typename T, typename U>
constexpr bool is_same_ptr() noexcept constexpr bool is_same_ptr() noexcept
{ {
#ifdef _MSC_VER
return true;
#else
if constexpr (std::is_void_v<T> || std::is_void_v<U> || std::is_same_v<T, U>) if constexpr (std::is_void_v<T> || std::is_void_v<U> || std::is_same_v<T, U>)
{ {
return true; return true;
} }
else if constexpr (std::is_convertible_v<U*, T*>) else if constexpr (std::is_convertible_v<U*, T*>)
{ {
constexpr auto u = std::addressof(sample<U>); return is_same_ptr_test<T, U>();
constexpr volatile void* x = u;
return static_cast<T*>(u) == x;
} }
else if constexpr (std::is_convertible_v<T*, U*>) else if constexpr (std::is_convertible_v<T*, U*>)
{ {
constexpr auto t = std::addressof(sample<T>); return is_same_ptr_test<U, T>();
constexpr volatile void* x = t;
return static_cast<U*>(t) == x;
} }
else
{ return !std::is_class_v<T> && !std::is_class_v<U> && !std::is_union_v<T> && !std::is_union_v<U>;
return false;
}
#endif
} }
template <typename T, typename U> template <typename T, typename U>
constexpr bool is_same_ptr_cast_v = std::is_convertible_v<U*, T*> && is_same_ptr<T, U>(); constexpr bool is_same_ptr_cast_v = std::is_convertible_v<U*, T*> && is_same_ptr<T, U>();
#ifndef _MSC_VER
#pragma GCC diagnostic pop
#endif
template <typename T> template <typename T>
class single_ptr; class single_ptr;