#pragma once #include #include #include #include "macros.hh" namespace where { #if 0 //XXX: I think this is fine? auto&& rvalue references seem to bind to const& references anyway? constexpr auto const& as_const( auto& t ) noexcept { return std::as_const(FORWARD(t)); } constexpr auto const&& as_const( auto&& t ) noexcept { using T = decltype(t); static_assert(!std::is_reference_t, "Bad decltype(auto&&)"); return static_cast&&>(t); } #endif template using add_const_reference_t = decltype((std::as_const(std::declval()))); template using add_const_pointer_t = decltype(std::addressof(std::as_const(std::declval()))); template concept is_polymorphic = requires(requires(T* ptr) { dynamic_cast(ptr); }); static_assert( std::is_lvalue_reference_v> and std::is_lvalue_reference_v> and std::is_lvalue_reference_v and std::is_lvalue_reference_v and std::is_same_v < add_const_reference_t&> , std::unique_ptr const& > , "add_const_reference_t is not perfectly forwarding"); template concept pointer_like = requires { typename std::pointer_traits

; typename std::pointer_traits

::element_type; typename std::pointer_traits

::pointer; }; template concept deref_to = pointer_like

and requires(P ptr) { // element type can be assigned to `T`. requires(std::is_convertible_v::element_type, T>); // Dereferencing the pointer can be assigned to `T`. { *ptr } noexcept(Noexcept) -> std::convertible_to::element_type>; //{ ptr <=> nullptr } noexcept(Noexcept) -> std::convertible_to< // { std::as_const(*ptr) } noexcept(Noexcept) -> std::convertible_to>; // { std::addressof(value) } -> std::convertible_to::pointer>; }; template concept may_deref_to = deref_to and requires(P ptr) { // The pointer is nullable { ptr } noexcept(Noexcept) -> std::convertible_to; { !ptr } noexcept(Noexcept) -> std::convertible_to; // The pointer can be constructed from `nullptr`. //{ nullptr } noexcept(Noexcept) -> std::convertible_to

; // The pointer can be assigned `nullptr`. //{ ptr = nullptr } noexcept(Noexcept); // The pointer is orderable. //{ ptr == ptr } noexcept(Noexcept) -> std::convertible_to; //{ ptr != ptr } noexcept(Noexcept) -> std::convertible_to; // The pointer is null-comparable { ptr == nullptr } noexcept(Noexcept) -> std::convertible_to; { ptr != nullptr } noexcept(Noexcept) -> std::convertible_to; }; // { std::as_const(*ptr) } noexcept -> std::convertible_to>; // { std::addressof(value) } noexcept -> std::convertible_to

; /*requires(std::is_convertible_v < add_const_reference_t< std::pointer_traits

::element_type > , add_const_reference_t< T > >); { std::as_const(*std::declval::pointer>()) } -> std::convertible_to::element_type>; //std::convertible_to< add_const_pointer_t<*/ //}; #if 0 (std::is_pointer_v

&& // P = ?* requires(P ptr) { { ptr } -> std::convertible_to; { static_cast(ptr) }; } ) or requires(P ptr, T value) { }; #endif }