new arg and inst conversions

This commit is contained in:
BlackMATov
2022-01-07 18:25:26 +07:00
parent b806ac7485
commit 4ec160d292
3 changed files with 287 additions and 184 deletions

View File

@@ -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_{};
};

View File

@@ -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&&>()};
}
}
}

View File

@@ -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));
}
}
}