#pragma once #include template class exact_type { T *p; public: operator bool() const = delete; // Conversion to void* variants is prohibited operator void *() const = delete; operator volatile void *() const = delete; operator const void *() const = delete; operator const volatile void *() const = delete; template bool operator<(U &&) const = delete; template bool operator<=(U &&) const = delete; template bool operator>(U &&) const = delete; template bool operator>=(U &&) const = delete; constexpr exact_type(T *t) : p(t) {} // Conversion to the exact type is permitted constexpr operator const T *() const { return p; } constexpr operator typename std::remove_const::type *() const { return p; } constexpr bool operator==(const T *rhs) const { return p == rhs; } [[nodiscard]] constexpr bool operator==(const exact_type &rhs) const = default; }; template class prohibit_void_ptr { public: // Return a proxy when the address is taken constexpr exact_type operator&() { return static_cast(this); } constexpr exact_type operator&() const { return static_cast(this); } };