You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
107 lines
3.6 KiB
107 lines
3.6 KiB
#pragma once
|
|
|
|
#include <memory>
|
|
#include <concepts>
|
|
#include <utility>
|
|
|
|
#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<T>, "Bad decltype(auto&&)");
|
|
|
|
return static_cast<std::add_const_t<T>&&>(t);
|
|
}
|
|
#endif
|
|
template<typename T>
|
|
using add_const_reference_t = decltype((std::as_const(std::declval<T>())));
|
|
|
|
template<typename T>
|
|
using add_const_pointer_t = decltype(std::addressof(std::as_const(std::declval<T>())));
|
|
|
|
template<typename T>
|
|
concept is_polymorphic = requires(requires(T* ptr) { dynamic_cast<void const*>(ptr); });
|
|
|
|
static_assert(
|
|
std::is_lvalue_reference_v<add_const_reference_t<int>>
|
|
and std::is_lvalue_reference_v<add_const_reference_t<int const&>>
|
|
and std::is_lvalue_reference_v<add_const_reference_t<int &&>
|
|
and std::is_lvalue_reference_v<add_const_reference_t<int const&&>
|
|
and std::is_same_v
|
|
< add_const_reference_t<std::unique_ptr<int>&>
|
|
, std::unique_ptr<int> const&
|
|
>
|
|
, "add_const_reference_t is not perfectly forwarding");
|
|
template<typename P>
|
|
concept pointer_like = requires {
|
|
typename std::pointer_traits<P>;
|
|
typename std::pointer_traits<P>::element_type;
|
|
typename std::pointer_traits<P>::pointer;
|
|
};
|
|
|
|
template<typename P, typename T, bool Noexcept = true>
|
|
concept deref_to = pointer_like<P>
|
|
and requires(P ptr) {
|
|
// element type can be assigned to `T`.
|
|
requires(std::is_convertible_v<std::pointer_traits<P>::element_type, T>);
|
|
|
|
// Dereferencing the pointer can be assigned to `T`.
|
|
{ *ptr } noexcept(Noexcept) -> std::convertible_to<std::pointer_traits<P>::element_type>;
|
|
|
|
//{ ptr <=> nullptr } noexcept(Noexcept) -> std::convertible_to<
|
|
|
|
// { std::as_const(*ptr) } noexcept(Noexcept) -> std::convertible_to<add_const_reference_t<T>>;
|
|
// { std::addressof(value) } -> std::convertible_to<std::pointer_traits<P>::pointer>;
|
|
};
|
|
|
|
template<typename P, typename T, bool Noexcept = true>
|
|
concept may_deref_to = deref_to<P, T, Noexcept>
|
|
and requires(P ptr) {
|
|
// The pointer is nullable
|
|
{ ptr } noexcept(Noexcept) -> std::convertible_to<bool>;
|
|
{ !ptr } noexcept(Noexcept) -> std::convertible_to<bool>;
|
|
|
|
// The pointer can be constructed from `nullptr`.
|
|
//{ nullptr } noexcept(Noexcept) -> std::convertible_to<P>;
|
|
|
|
// The pointer can be assigned `nullptr`.
|
|
//{ ptr = nullptr } noexcept(Noexcept);
|
|
|
|
// The pointer is orderable.
|
|
//{ ptr == ptr } noexcept(Noexcept) -> std::convertible_to<bool>;
|
|
//{ ptr != ptr } noexcept(Noexcept) -> std::convertible_to<bool>;
|
|
|
|
// The pointer is null-comparable
|
|
{ ptr == nullptr } noexcept(Noexcept) -> std::convertible_to<bool>;
|
|
{ ptr != nullptr } noexcept(Noexcept) -> std::convertible_to<bool>;
|
|
};
|
|
// { std::as_const(*ptr) } noexcept -> std::convertible_to<add_const_reference_t<T>>;
|
|
// { std::addressof(value) } noexcept -> std::convertible_to<P>;
|
|
/*requires(std::is_convertible_v
|
|
< add_const_reference_t< std::pointer_traits<P>::element_type >
|
|
, add_const_reference_t< T >
|
|
>);
|
|
{ std::as_const(*std::declval<std::pointer_traits<P>::pointer>()) }
|
|
-> std::convertible_to<std::pointer_traits<P>::element_type>;
|
|
//std::convertible_to< add_const_pointer_t<*/
|
|
//};
|
|
|
|
#if 0
|
|
(std::is_pointer_v<P> &&
|
|
// P = ?*
|
|
requires(P ptr) {
|
|
{ ptr } -> std::convertible_to<T const*>;
|
|
{ static_cast<T*>(ptr) };
|
|
}
|
|
)
|
|
or requires(P ptr, T value) {
|
|
|
|
};
|
|
#endif
|
|
}
|