mirror of
https://github.com/BlackMATov/meta.hpp.git
synced 2025-12-15 03:45:30 +07:00
new arg and inst conversions
This commit is contained in:
@@ -68,7 +68,9 @@ namespace meta_hpp::detail
|
||||
|
||||
template < typename T >
|
||||
concept uvalue_kind =
|
||||
std::same_as<T, arg_base> ||
|
||||
std::same_as<T, arg> ||
|
||||
std::same_as<T, inst_base> ||
|
||||
std::same_as<T, inst> ||
|
||||
std::same_as<T, value>;
|
||||
|
||||
@@ -218,20 +220,20 @@ namespace meta_hpp::detail
|
||||
public:
|
||||
arg_base() = delete;
|
||||
|
||||
arg_base(arg_base&&) = delete;
|
||||
arg_base& operator=(arg_base&&) = delete;
|
||||
arg_base(arg_base&&) = default;
|
||||
arg_base(const arg_base&) = default;
|
||||
|
||||
arg_base(const arg_base&) = delete;
|
||||
arg_base& operator=(arg_base&&) = delete;
|
||||
arg_base& operator=(const arg_base&) = delete;
|
||||
|
||||
template < typename T, std::enable_if_t<
|
||||
(std::is_lvalue_reference_v<T>)
|
||||
, int> = 0 >
|
||||
virtual ~arg_base() = default;
|
||||
|
||||
template < arg_lvalue_ref_kind T >
|
||||
requires decay_non_uvalue_kind<T>
|
||||
explicit arg_base(type_list<T>);
|
||||
|
||||
template < typename T, std::enable_if_t<
|
||||
(std::is_rvalue_reference_v<T> || !std::is_reference_v<T>)
|
||||
, int> = 0 >
|
||||
template < arg_rvalue_ref_kind T >
|
||||
requires decay_non_uvalue_kind<T>
|
||||
explicit arg_base(type_list<T>);
|
||||
|
||||
explicit arg_base(value& v);
|
||||
@@ -240,15 +242,15 @@ namespace meta_hpp::detail
|
||||
explicit arg_base(value&& v);
|
||||
explicit arg_base(const value&& v);
|
||||
|
||||
bool is_const() const noexcept;
|
||||
bool is_lvalue() const noexcept;
|
||||
bool is_rvalue() const noexcept;
|
||||
[[nodiscard]] bool is_const() const noexcept;
|
||||
[[nodiscard]] bool is_lvalue() const noexcept;
|
||||
[[nodiscard]] bool is_rvalue() const noexcept;
|
||||
|
||||
ref_types get_ref_type() const noexcept;
|
||||
const any_type& get_raw_type() const noexcept;
|
||||
[[nodiscard]] ref_types get_ref_type() const noexcept;
|
||||
[[nodiscard]] const any_type& get_raw_type() const noexcept;
|
||||
|
||||
template < typename To >
|
||||
bool can_cast_to() const noexcept;
|
||||
[[nodiscard]] bool can_cast_to() const noexcept;
|
||||
private:
|
||||
ref_types ref_type_{};
|
||||
any_type raw_type_{};
|
||||
@@ -261,24 +263,22 @@ namespace meta_hpp::detail
|
||||
public:
|
||||
arg() = delete;
|
||||
|
||||
arg(arg&&) = delete;
|
||||
arg& operator=(arg&&) = delete;
|
||||
arg(arg&&) = default;
|
||||
arg(const arg&) = default;
|
||||
|
||||
arg(const arg&) = delete;
|
||||
arg& operator=(arg&&) = delete;
|
||||
arg& operator=(const arg&) = delete;
|
||||
|
||||
template < typename T, typename Tp = std::decay_t<T>
|
||||
, std::enable_if_t<std::is_same_v<Tp, value>, int> = 0 >
|
||||
~arg() override = default;
|
||||
|
||||
template < decay_value_kind T >
|
||||
explicit arg(T&& v);
|
||||
|
||||
template < typename T, typename Tp = std::decay_t<T>
|
||||
, std::enable_if_t<!std::is_same_v<Tp, arg>, int> = 0
|
||||
, std::enable_if_t<!std::is_same_v<Tp, inst>, int> = 0
|
||||
, std::enable_if_t<!std::is_same_v<Tp, value>, int> = 0 >
|
||||
template < decay_non_uvalue_kind T >
|
||||
explicit arg(T&& v);
|
||||
|
||||
template < typename To >
|
||||
To cast() const;
|
||||
[[nodiscard]] To cast() const;
|
||||
private:
|
||||
void* data_{};
|
||||
};
|
||||
@@ -297,21 +297,18 @@ namespace meta_hpp::detail
|
||||
public:
|
||||
inst_base() = delete;
|
||||
|
||||
inst_base(inst_base&&) = delete;
|
||||
inst_base& operator=(inst_base&&) = delete;
|
||||
inst_base(inst_base&&) = default;
|
||||
inst_base(const inst_base&) = default;
|
||||
|
||||
inst_base(const inst_base&) = delete;
|
||||
inst_base& operator=(inst_base&&) = delete;
|
||||
inst_base& operator=(const inst_base&) = delete;
|
||||
|
||||
template < typename T, std::enable_if_t<
|
||||
(std::is_lvalue_reference_v<T> && std::is_class_v<std::remove_reference_t<T>>)
|
||||
, int> = 0>
|
||||
virtual ~inst_base() = default;
|
||||
|
||||
template < inst_class_lvalue_ref_kind T >
|
||||
explicit inst_base(type_list<T>);
|
||||
|
||||
template < typename T, std::enable_if_t<
|
||||
(std::is_class_v<T>) ||
|
||||
(std::is_rvalue_reference_v<T> && std::is_class_v<std::remove_reference_t<T>>)
|
||||
, int> = 0>
|
||||
template < inst_class_rvalue_ref_kind T >
|
||||
explicit inst_base(type_list<T>);
|
||||
|
||||
explicit inst_base(value& v);
|
||||
@@ -320,18 +317,15 @@ namespace meta_hpp::detail
|
||||
explicit inst_base(value&& v);
|
||||
explicit inst_base(const value&& v);
|
||||
|
||||
bool is_const() const noexcept;
|
||||
bool is_lvalue() const noexcept;
|
||||
bool is_rvalue() const noexcept;
|
||||
[[nodiscard]] bool is_const() const noexcept;
|
||||
[[nodiscard]] bool is_lvalue() const noexcept;
|
||||
[[nodiscard]] bool is_rvalue() const noexcept;
|
||||
|
||||
ref_types get_ref_type() const noexcept;
|
||||
const class_type& get_raw_type() const noexcept;
|
||||
[[nodiscard]] ref_types get_ref_type() const noexcept;
|
||||
[[nodiscard]] const class_type& get_raw_type() const noexcept;
|
||||
|
||||
template < typename To, std::enable_if_t<
|
||||
(std::is_class_v<To>) ||
|
||||
(std::is_reference_v<To> && std::is_class_v<std::remove_reference_t<To>>)
|
||||
, int> = 0>
|
||||
bool can_cast_to() const noexcept;
|
||||
template < inst_class_ref_kind Q >
|
||||
[[nodiscard]] bool can_cast_to() const noexcept;
|
||||
private:
|
||||
ref_types ref_type_{};
|
||||
class_type raw_type_{};
|
||||
@@ -344,27 +338,22 @@ namespace meta_hpp::detail
|
||||
public:
|
||||
inst() = delete;
|
||||
|
||||
inst(inst&&) = delete;
|
||||
inst& operator=(inst&&) = delete;
|
||||
inst(inst&&) = default;
|
||||
inst(const inst&) = default;
|
||||
|
||||
inst(const inst&) = delete;
|
||||
inst& operator=(inst&&) = delete;
|
||||
inst& operator=(const inst&) = delete;
|
||||
|
||||
template < typename T, typename Tp = std::decay_t<T>
|
||||
, std::enable_if_t<std::is_same_v<Tp, value>, int> = 0 >
|
||||
~inst() override = default;
|
||||
|
||||
template < decay_value_kind T >
|
||||
explicit inst(T&& v);
|
||||
|
||||
template < typename T, class_kind Tp = std::decay_t<T>
|
||||
, std::enable_if_t<!std::is_same_v<Tp, arg>, int> = 0
|
||||
, std::enable_if_t<!std::is_same_v<Tp, inst>, int> = 0
|
||||
, std::enable_if_t<!std::is_same_v<Tp, value>, int> = 0 >
|
||||
template < decay_non_uvalue_kind T >
|
||||
explicit inst(T&& v);
|
||||
|
||||
template < typename To, std::enable_if_t<
|
||||
(std::is_class_v<To>) ||
|
||||
(std::is_reference_v<To> && std::is_class_v<std::remove_reference_t<To>>)
|
||||
, int> = 0>
|
||||
decltype(auto) cast() const;
|
||||
template < inst_class_ref_kind Q >
|
||||
[[nodiscard]] decltype(auto) cast() const;
|
||||
private:
|
||||
void* data_{};
|
||||
};
|
||||
|
||||
@@ -11,18 +11,22 @@
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
template < typename T, std::enable_if_t<
|
||||
(std::is_lvalue_reference_v<T>)
|
||||
, int> >
|
||||
template < arg_lvalue_ref_kind T >
|
||||
requires decay_non_uvalue_kind<T>
|
||||
// NOLINTNEXTLINE(readability-named-parameter)
|
||||
arg_base::arg_base(type_list<T>)
|
||||
: ref_type_{std::is_const_v<std::remove_reference_t<T>> ? ref_types::const_lvalue : ref_types::lvalue}
|
||||
: ref_type_{std::is_const_v<std::remove_reference_t<T>>
|
||||
? ref_types::const_lvalue
|
||||
: ref_types::lvalue}
|
||||
, raw_type_{resolve_type<std::remove_cvref_t<T>>()} {}
|
||||
|
||||
template < typename T, std::enable_if_t<
|
||||
(std::is_rvalue_reference_v<T> || !std::is_reference_v<T>)
|
||||
, int> >
|
||||
template < arg_rvalue_ref_kind T >
|
||||
requires decay_non_uvalue_kind<T>
|
||||
// NOLINTNEXTLINE(readability-named-parameter)
|
||||
arg_base::arg_base(type_list<T>)
|
||||
: ref_type_{std::is_const_v<std::remove_reference_t<T>> ? ref_types::const_rvalue : ref_types::rvalue}
|
||||
: ref_type_{std::is_const_v<std::remove_reference_t<T>>
|
||||
? ref_types::const_rvalue
|
||||
: ref_types::rvalue}
|
||||
, raw_type_{resolve_type<std::remove_cvref_t<T>>()} {}
|
||||
|
||||
inline arg_base::arg_base(value& v)
|
||||
@@ -65,6 +69,7 @@ namespace meta_hpp::detail
|
||||
}
|
||||
|
||||
template < typename To >
|
||||
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
|
||||
bool arg_base::can_cast_to() const noexcept {
|
||||
using to_raw_type_cv = std::remove_reference_t<To>;
|
||||
using to_raw_type = std::remove_cv_t<to_raw_type_cv>;
|
||||
@@ -73,112 +78,176 @@ namespace meta_hpp::detail
|
||||
!(std::is_reference_v<To> && std::is_pointer_v<to_raw_type>),
|
||||
"references to pointers are not supported yet");
|
||||
|
||||
const auto check_qualifiers = [this](){
|
||||
switch ( get_ref_type() ) {
|
||||
case ref_types::lvalue: return std::is_convertible_v<to_raw_type&, To>;
|
||||
case ref_types::const_lvalue: return std::is_convertible_v<const to_raw_type&, To>;
|
||||
case ref_types::rvalue: return std::is_convertible_v<to_raw_type&&, To>;
|
||||
case ref_types::const_rvalue: return std::is_convertible_v<const to_raw_type&&, To>;
|
||||
}
|
||||
const any_type& from_type = get_raw_type();
|
||||
const any_type& to_type = resolve_type<to_raw_type>();
|
||||
|
||||
const auto is_a = [](const any_type& base, const any_type& derived){
|
||||
return (base == derived)
|
||||
|| (base.is_class() && derived.is_class() && base.as_class().is_base_of(derived.as_class()));
|
||||
};
|
||||
|
||||
const auto check_convertible = [this](){
|
||||
const auto is_a = [](const any_type& base, const any_type& derived){
|
||||
return (base == derived)
|
||||
|| (base.is_class() && derived.is_class() && base.as_class().is_base_of(derived.as_class()));
|
||||
};
|
||||
|
||||
const any_type& from_type = get_raw_type();
|
||||
const any_type& to_type = resolve_type<to_raw_type>();
|
||||
|
||||
if ( is_a(to_type, from_type) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( std::is_lvalue_reference_v<To> && !std::is_const_v<to_raw_type_cv> ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( from_type.is_pointer() && to_type.is_pointer() ) {
|
||||
const pointer_type& from_type_ptr = from_type.as_pointer();
|
||||
const bool from_type_ptr_readonly = from_type_ptr.get_flags().has(pointer_flags::is_readonly);
|
||||
|
||||
if constexpr ( std::is_pointer_v<To> ) {
|
||||
if ( to_type.is_pointer() && from_type.is_pointer() ) {
|
||||
const pointer_type& to_type_ptr = to_type.as_pointer();
|
||||
const bool to_type_ptr_readonly = to_type_ptr.get_flags().has(pointer_flags::is_readonly);
|
||||
|
||||
return to_type_ptr_readonly >= from_type_ptr_readonly
|
||||
&& is_a(to_type_ptr.get_data_type(), from_type_ptr.get_data_type());
|
||||
const pointer_type& from_type_ptr = from_type.as_pointer();
|
||||
const bool from_type_ptr_readonly = from_type_ptr.get_flags().has(pointer_flags::is_readonly);
|
||||
|
||||
const any_type& to_data_type = to_type_ptr.get_data_type();
|
||||
const any_type& from_data_type = from_type_ptr.get_data_type();
|
||||
|
||||
if ( is_a(to_data_type, from_data_type) && to_type_ptr_readonly >= from_type_ptr_readonly ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
if constexpr ( std::is_reference_v<To> ) {
|
||||
const auto is_convertible = [this](){
|
||||
switch ( get_ref_type() ) {
|
||||
case ref_types::lvalue:
|
||||
return std::is_convertible_v<noncopyable&, copy_cvref_t<To, noncopyable>>;
|
||||
case ref_types::const_lvalue:
|
||||
return std::is_convertible_v<const noncopyable&, copy_cvref_t<To, noncopyable>>;
|
||||
case ref_types::rvalue:
|
||||
return std::is_convertible_v<noncopyable&&, copy_cvref_t<To, noncopyable>>;
|
||||
case ref_types::const_rvalue:
|
||||
return std::is_convertible_v<const noncopyable&&, copy_cvref_t<To, noncopyable>>;
|
||||
}
|
||||
};
|
||||
|
||||
return check_qualifiers() && check_convertible();
|
||||
if ( is_a(to_type, from_type) && is_convertible() ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr ( !std::is_pointer_v<To> && !std::is_reference_v<To> ) {
|
||||
const auto is_constructible = [this](){
|
||||
switch ( get_ref_type() ) {
|
||||
case ref_types::lvalue:
|
||||
return std::is_constructible_v<To, to_raw_type&> && can_cast_to<to_raw_type&>();
|
||||
case ref_types::const_lvalue:
|
||||
return std::is_constructible_v<To, const to_raw_type&> && can_cast_to<const to_raw_type&>();
|
||||
case ref_types::rvalue:
|
||||
return std::is_constructible_v<To, to_raw_type&&> && can_cast_to<to_raw_type&&>();
|
||||
case ref_types::const_rvalue:
|
||||
return std::is_constructible_v<To, const to_raw_type&&> && can_cast_to<const to_raw_type&&>();
|
||||
}
|
||||
};
|
||||
|
||||
if ( is_a(to_type, from_type) && is_constructible() ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
template < typename T, typename Tp
|
||||
, std::enable_if_t<std::is_same_v<Tp, value>, int> >
|
||||
template < decay_value_kind T >
|
||||
arg::arg(T&& v)
|
||||
: arg_base{std::forward<T>(v)}
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
|
||||
, data_{const_cast<void*>(v.data())} {}
|
||||
|
||||
template < typename T, typename Tp
|
||||
, std::enable_if_t<!std::is_same_v<Tp, arg>, int>
|
||||
, std::enable_if_t<!std::is_same_v<Tp, inst>, int>
|
||||
, std::enable_if_t<!std::is_same_v<Tp, value>, int> >
|
||||
template < decay_non_uvalue_kind T >
|
||||
arg::arg(T&& v)
|
||||
: arg_base{type_list<T&&>{}}
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
|
||||
, data_{const_cast<std::remove_cvref_t<T>*>(std::addressof(v))} {}
|
||||
|
||||
template < typename To >
|
||||
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
|
||||
To arg::cast() const {
|
||||
if ( !can_cast_to<To>() ) {
|
||||
throw std::logic_error("bad argument cast");
|
||||
}
|
||||
|
||||
using to_raw_type_cv = std::remove_reference_t<To>;
|
||||
using to_raw_type = std::remove_cv_t<to_raw_type_cv>;
|
||||
|
||||
const any_type& from_type = get_raw_type();
|
||||
const any_type& to_type = resolve_type<to_raw_type>();
|
||||
|
||||
if constexpr ( std::is_pointer_v<To> ) {
|
||||
return *static_cast<To*>(data_);
|
||||
if ( to_type.is_pointer() && from_type.is_pointer() ) {
|
||||
const pointer_type& to_type_ptr = to_type.as_pointer();
|
||||
const pointer_type& from_type_ptr = from_type.as_pointer();
|
||||
|
||||
const any_type& to_data_type = to_type_ptr.get_data_type();
|
||||
const any_type& from_data_type = from_type_ptr.get_data_type();
|
||||
|
||||
void** from_data_ptr = static_cast<void**>(data_);
|
||||
|
||||
if ( to_data_type == from_data_type ) {
|
||||
void* to_data_ptr = *from_data_ptr;
|
||||
return static_cast<to_raw_type_cv>(to_data_ptr);
|
||||
}
|
||||
|
||||
if ( to_data_type.is_class() && from_data_type.is_class() ) {
|
||||
const class_type& to_data_class = to_data_type.as_class();
|
||||
const class_type& from_data_class = from_data_type.as_class();
|
||||
|
||||
void* to_data_ptr = detail::pointer_upcast(*from_data_ptr, from_data_class, to_data_class);
|
||||
return static_cast<to_raw_type_cv>(to_data_ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr ( std::is_reference_v<To> ) {
|
||||
using raw_type = std::remove_cvref_t<To>;
|
||||
if ( to_type == from_type ) {
|
||||
void* to_ptr = static_cast<void*>(data_);
|
||||
|
||||
if constexpr ( std::is_lvalue_reference_v<To> ) {
|
||||
return *static_cast<raw_type*>(data_);
|
||||
if constexpr ( std::is_lvalue_reference_v<To> ) {
|
||||
return *static_cast<to_raw_type_cv*>(to_ptr);
|
||||
}
|
||||
|
||||
if constexpr ( std::is_rvalue_reference_v<To> ) {
|
||||
return std::move(*static_cast<to_raw_type_cv*>(to_ptr));
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr ( std::is_rvalue_reference_v<To> ) {
|
||||
return std::move(*static_cast<raw_type*>(data_));
|
||||
if ( to_type.is_class() && from_type.is_class() ) {
|
||||
const class_type& to_class = to_type.as_class();
|
||||
const class_type& from_class = from_type.as_class();
|
||||
|
||||
void* to_ptr = detail::pointer_upcast(data_, from_class, to_class);
|
||||
|
||||
if constexpr ( std::is_lvalue_reference_v<To> ) {
|
||||
return *static_cast<to_raw_type_cv*>(to_ptr);
|
||||
}
|
||||
|
||||
if constexpr ( std::is_rvalue_reference_v<To> ) {
|
||||
return std::move(*static_cast<to_raw_type_cv*>(to_ptr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr ( !std::is_pointer_v<To> && !std::is_reference_v<To> ) {
|
||||
using raw_type = std::remove_cv_t<To>;
|
||||
|
||||
if ( get_ref_type() == ref_types::lvalue ) {
|
||||
if constexpr ( std::is_constructible_v<To, raw_type&> ) {
|
||||
return To{*static_cast<raw_type*>(data_)};
|
||||
if constexpr ( std::is_constructible_v<To, to_raw_type&> ) {
|
||||
if ( get_ref_type() == ref_types::lvalue ) {
|
||||
return To{cast<to_raw_type&>()};
|
||||
}
|
||||
}
|
||||
|
||||
if ( get_ref_type() == ref_types::const_lvalue ) {
|
||||
if constexpr ( std::is_constructible_v<To, const raw_type&> ) {
|
||||
return To{std::as_const(*static_cast<raw_type*>(data_))};
|
||||
if constexpr ( std::is_constructible_v<To, const to_raw_type&> ) {
|
||||
if ( get_ref_type() == ref_types::const_lvalue ) {
|
||||
return To{cast<const to_raw_type&>()};
|
||||
}
|
||||
}
|
||||
|
||||
if ( get_ref_type() == ref_types::rvalue ) {
|
||||
if constexpr ( std::is_constructible_v<To, raw_type&&> ) {
|
||||
return To{std::move(*static_cast<raw_type*>(data_))};
|
||||
if constexpr ( std::is_constructible_v<To, to_raw_type&&> ) {
|
||||
if ( get_ref_type() == ref_types::rvalue ) {
|
||||
return To{cast<to_raw_type&&>()};
|
||||
}
|
||||
}
|
||||
|
||||
if ( get_ref_type() == ref_types::const_rvalue ) {
|
||||
if constexpr ( std::is_constructible_v<To, const raw_type&&> ) {
|
||||
return To{std::move(std::as_const(*static_cast<raw_type*>(data_)))};
|
||||
if constexpr ( std::is_constructible_v<To, const to_raw_type&&> ) {
|
||||
if ( get_ref_type() == ref_types::const_rvalue ) {
|
||||
return To{cast<const to_raw_type&&>()};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,19 +11,71 @@
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
template < typename T, std::enable_if_t<
|
||||
(std::is_lvalue_reference_v<T> && std::is_class_v<std::remove_reference_t<T>>)
|
||||
, int> >
|
||||
namespace impl
|
||||
{
|
||||
template < inst_class_ref_kind Q, bool is_const, bool is_lvalue, bool is_rvalue >
|
||||
struct inst_traits_impl;
|
||||
|
||||
template < inst_class_ref_kind Q >
|
||||
struct inst_traits_impl<Q, false, false, false> {
|
||||
using class_type = std::remove_cvref_t<Q>;
|
||||
using method_type = void(class_type::*)();
|
||||
};
|
||||
|
||||
template < inst_class_ref_kind Q >
|
||||
struct inst_traits_impl<Q, false, true, false> {
|
||||
using class_type = std::remove_cvref_t<Q>;
|
||||
using method_type = void(class_type::*)() &;
|
||||
};
|
||||
|
||||
template < inst_class_ref_kind Q >
|
||||
struct inst_traits_impl<Q, false, false, true> {
|
||||
using class_type = std::remove_cvref_t<Q>;
|
||||
using method_type = void(class_type::*)() &&;
|
||||
};
|
||||
|
||||
template < inst_class_ref_kind Q >
|
||||
struct inst_traits_impl<Q, true, false, false> {
|
||||
using class_type = std::remove_cvref_t<Q>;
|
||||
using method_type = void(class_type::*)() const;
|
||||
};
|
||||
|
||||
template < inst_class_ref_kind Q >
|
||||
struct inst_traits_impl<Q, true, true, false> {
|
||||
using class_type = std::remove_cvref_t<Q>;
|
||||
using method_type = void(class_type::*)() const &;
|
||||
};
|
||||
|
||||
template < inst_class_ref_kind Q >
|
||||
struct inst_traits_impl<Q, true, false, true> {
|
||||
using class_type = std::remove_cvref_t<Q>;
|
||||
using method_type = void(class_type::*)() const &&;
|
||||
};
|
||||
}
|
||||
|
||||
template < inst_class_ref_kind Q >
|
||||
struct inst_traits final : impl::inst_traits_impl<Q,
|
||||
cvref_traits<Q>::is_const,
|
||||
cvref_traits<Q>::is_lvalue,
|
||||
cvref_traits<Q>::is_rvalue> {};
|
||||
}
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
template < inst_class_lvalue_ref_kind T >
|
||||
// NOLINTNEXTLINE(readability-named-parameter)
|
||||
inst_base::inst_base(type_list<T>)
|
||||
: ref_type_{std::is_const_v<std::remove_reference_t<T>> ? ref_types::const_lvalue : ref_types::lvalue}
|
||||
: ref_type_{std::is_const_v<std::remove_reference_t<T>>
|
||||
? ref_types::const_lvalue
|
||||
: ref_types::lvalue}
|
||||
, raw_type_{resolve_type<std::remove_cvref_t<T>>()} {}
|
||||
|
||||
template < typename T, std::enable_if_t<
|
||||
(std::is_class_v<T>) ||
|
||||
(std::is_rvalue_reference_v<T> && std::is_class_v<std::remove_reference_t<T>>)
|
||||
, int> >
|
||||
template < inst_class_rvalue_ref_kind T >
|
||||
// NOLINTNEXTLINE(readability-named-parameter)
|
||||
inst_base::inst_base(type_list<T>)
|
||||
: ref_type_{std::is_const_v<std::remove_reference_t<T>> ? ref_types::const_rvalue : ref_types::rvalue}
|
||||
: ref_type_{std::is_const_v<std::remove_reference_t<T>>
|
||||
? ref_types::const_rvalue
|
||||
: ref_types::rvalue}
|
||||
, raw_type_{resolve_type<std::remove_cvref_t<T>>()} {}
|
||||
|
||||
inline inst_base::inst_base(value& v)
|
||||
@@ -81,80 +133,73 @@ namespace meta_hpp::detail
|
||||
return raw_type_;
|
||||
}
|
||||
|
||||
template < typename To, std::enable_if_t<
|
||||
(std::is_class_v<To>) ||
|
||||
(std::is_reference_v<To> && std::is_class_v<std::remove_reference_t<To>>)
|
||||
, int> >
|
||||
template < inst_class_ref_kind Q >
|
||||
bool inst_base::can_cast_to() const noexcept {
|
||||
using to_raw_type = std::remove_cvref_t<To>;
|
||||
using to_raw_type_cv = std::remove_reference_t<To>;
|
||||
using inst_class = typename inst_traits<Q>::class_type;
|
||||
using inst_method = typename inst_traits<Q>::method_type;
|
||||
|
||||
if constexpr ( !std::is_const_v<to_raw_type_cv> ) {
|
||||
if ( is_const() ) {
|
||||
return false;
|
||||
const class_type& from_type = get_raw_type();
|
||||
const class_type& to_type = resolve_type<inst_class>();
|
||||
|
||||
const auto is_a = [](const class_type& base, const class_type& derived){
|
||||
return base == derived || base.is_base_of(derived);
|
||||
};
|
||||
|
||||
const auto is_invocable = [this](){
|
||||
switch ( get_ref_type() ) {
|
||||
case ref_types::lvalue:
|
||||
return std::is_invocable_v<inst_method, inst_class&>;
|
||||
case ref_types::const_lvalue:
|
||||
return std::is_invocable_v<inst_method, const inst_class&>;
|
||||
case ref_types::rvalue:
|
||||
return std::is_invocable_v<inst_method, inst_class&&>;
|
||||
case ref_types::const_rvalue:
|
||||
return std::is_invocable_v<inst_method, const inst_class&&>;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if constexpr ( std::is_reference_v<To> ) {
|
||||
const auto check_qualifiers = [](ref_types self_ref_type){
|
||||
switch ( self_ref_type ) {
|
||||
case ref_types::lvalue: return std::is_convertible_v<to_raw_type&, To>;
|
||||
case ref_types::const_lvalue: return std::is_convertible_v<const to_raw_type&, To>;
|
||||
case ref_types::rvalue: return std::is_convertible_v<to_raw_type&&, To>;
|
||||
case ref_types::const_rvalue: return std::is_convertible_v<const to_raw_type&&, To>;
|
||||
}
|
||||
};
|
||||
|
||||
if ( !check_qualifiers(get_ref_type()) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return get_raw_type() == resolve_type<to_raw_type>()
|
||||
|| get_raw_type().is_derived_from(resolve_type<to_raw_type>());
|
||||
return is_a(to_type, from_type) && is_invocable();
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
template < typename T, typename Tp
|
||||
, std::enable_if_t<std::is_same_v<Tp, value>, int> >
|
||||
template < decay_value_kind T >
|
||||
inst::inst(T&& v)
|
||||
: inst_base{std::forward<T>(v)}
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
|
||||
, data_{const_cast<void*>(v.data())} {}
|
||||
|
||||
template < typename T, class_kind Tp
|
||||
, std::enable_if_t<!std::is_same_v<Tp, arg>, int>
|
||||
, std::enable_if_t<!std::is_same_v<Tp, inst>, int>
|
||||
, std::enable_if_t<!std::is_same_v<Tp, value>, int> >
|
||||
template < decay_non_uvalue_kind T >
|
||||
inst::inst(T&& v)
|
||||
: inst_base{type_list<T&&>{}}
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
|
||||
, data_{const_cast<std::remove_cvref_t<T>*>(std::addressof(v))} {}
|
||||
|
||||
template < typename To, std::enable_if_t<
|
||||
(std::is_class_v<To>) ||
|
||||
(std::is_reference_v<To> && std::is_class_v<std::remove_reference_t<To>>)
|
||||
, int> >
|
||||
template < inst_class_ref_kind Q >
|
||||
decltype(auto) inst::cast() const {
|
||||
if ( !can_cast_to<To>() ) {
|
||||
if ( !can_cast_to<Q>() ) {
|
||||
throw std::logic_error("bad instance cast");
|
||||
}
|
||||
|
||||
if constexpr ( std::is_reference_v<To> ) {
|
||||
using raw_type_with_cv = std::remove_reference_t<To>;
|
||||
using inst_class_cv = std::remove_reference_t<Q>;
|
||||
using inst_class = std::remove_cv_t<inst_class_cv>;
|
||||
|
||||
if constexpr ( std::is_lvalue_reference_v<To> ) {
|
||||
return *static_cast<raw_type_with_cv*>(data_);
|
||||
}
|
||||
const class_type& from_type = get_raw_type();
|
||||
const class_type& to_type = resolve_type<inst_class>();
|
||||
|
||||
if constexpr ( std::is_rvalue_reference_v<To> ) {
|
||||
return std::move(*static_cast<raw_type_with_cv*>(data_));
|
||||
}
|
||||
void* to_ptr = detail::pointer_upcast(data_, from_type, to_type);
|
||||
|
||||
if constexpr ( !std::is_reference_v<Q> ) {
|
||||
return *static_cast<inst_class_cv*>(to_ptr);
|
||||
}
|
||||
|
||||
if constexpr ( !std::is_reference_v<To>) {
|
||||
using raw_type_with_cv = To;
|
||||
return *static_cast<raw_type_with_cv*>(data_);
|
||||
if constexpr ( std::is_lvalue_reference_v<Q> ) {
|
||||
return *static_cast<inst_class_cv*>(to_ptr);
|
||||
}
|
||||
|
||||
if constexpr ( std::is_rvalue_reference_v<Q> ) {
|
||||
return std::move(*static_cast<inst_class_cv*>(to_ptr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user