diff --git a/develop/singles/headers/meta.hpp/meta_all.hpp b/develop/singles/headers/meta.hpp/meta_all.hpp index 6c77f83..4850124 100644 --- a/develop/singles/headers/meta.hpp/meta_all.hpp +++ b/develop/singles/headers/meta.hpp/meta_all.hpp @@ -5311,6 +5311,11 @@ namespace meta_hpp::detail } template < typename To > + requires(std::is_pointer_v) + [[nodiscard]] bool can_cast_to() const noexcept; + + template < typename To > + requires(!std::is_pointer_v) [[nodiscard]] bool can_cast_to() const noexcept; private: @@ -5346,6 +5351,11 @@ namespace meta_hpp::detail , data_{const_cast*>(std::addressof(v))} {} template < typename To > + requires(std::is_pointer_v) + [[nodiscard]] To cast() const; + + template < typename To > + requires(!std::is_pointer_v) [[nodiscard]] To cast() const; private: @@ -5356,8 +5366,63 @@ namespace meta_hpp::detail namespace meta_hpp::detail { template < typename To > - // NOLINTNEXTLINE(*-cognitive-complexity) - bool uarg_base::can_cast_to() const noexcept { + requires(std::is_pointer_v) + [[nodiscard]] bool uarg_base::can_cast_to() const noexcept { + using to_raw_type_cv = std::remove_reference_t; + using to_raw_type = std::remove_cv_t; + + const any_type& from_type = get_raw_type(); + const any_type& to_type = resolve_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())); + }; + + if ( from_type.is_nullptr() && to_type.is_pointer() ) { + return true; + } + + if ( to_type.is_pointer() && from_type.is_array() ) { + 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); + + const array_type& from_type_array = from_type.as_array(); + const bool from_type_array_readonly = is_ref_const(); + + const any_type& to_data_type = to_type_ptr.get_data_type(); + const any_type& from_data_type = from_type_array.get_data_type(); + + if ( to_type_ptr_readonly >= from_type_array_readonly ) { + if ( to_data_type.is_void() || is_a(to_data_type, from_data_type) ) { + return true; + } + } + } + + 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); + + 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 ( to_type_ptr_readonly >= from_type_ptr_readonly ) { + if ( to_data_type.is_void() || is_a(to_data_type, from_data_type) ) { + return true; + } + } + } + + return false; + } + + template < typename To > + requires(!std::is_pointer_v) + [[nodiscard]] bool uarg_base::can_cast_to() const noexcept { using to_raw_type_cv = std::remove_reference_t; using to_raw_type = std::remove_cv_t; @@ -5374,82 +5439,42 @@ namespace meta_hpp::detail || (base.is_class() && derived.is_class() && base.as_class().is_base_of(derived.as_class())); }; - if constexpr ( std::is_pointer_v ) { - if ( to_type.is_pointer() && from_type.is_nullptr() ) { - return true; + const auto is_convertible_to_ref = [this](type_list) { + switch ( get_ref_type() ) { + case ref_types::lvalue: + return std::is_convertible_v>; + case ref_types::const_lvalue: + return std::is_convertible_v>; + case ref_types::rvalue: + return std::is_convertible_v>; + case ref_types::const_rvalue: + return std::is_convertible_v>; } + return false; + }; - if ( to_type.is_pointer() && from_type.is_array() ) { - 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); - - const array_type& from_type_array = from_type.as_array(); - const bool from_type_array_readonly = is_ref_const(); - - const any_type& to_data_type = to_type_ptr.get_data_type(); - const any_type& from_data_type = from_type_array.get_data_type(); - - if ( to_type_ptr_readonly >= from_type_array_readonly ) { - if ( to_data_type.is_void() || is_a(to_data_type, from_data_type) ) { - return true; - } - } + const auto is_constructible_from_type = [this, &is_convertible_to_ref](type_list) { + switch ( get_ref_type() ) { + case ref_types::lvalue: + return std::is_constructible_v && is_convertible_to_ref(type_list{}); + case ref_types::const_lvalue: + return std::is_constructible_v && is_convertible_to_ref(type_list{}); + case ref_types::rvalue: + return std::is_constructible_v && is_convertible_to_ref(type_list{}); + case ref_types::const_rvalue: + return std::is_constructible_v && is_convertible_to_ref(type_list{}); } - - 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); - - 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 ( to_type_ptr_readonly >= from_type_ptr_readonly ) { - if ( to_data_type.is_void() || is_a(to_data_type, from_data_type) ) { - return true; - } - } - } - } + return false; + }; if constexpr ( std::is_reference_v ) { - const auto is_convertible = [this]() { - switch ( get_ref_type() ) { - case ref_types::lvalue: - return std::is_convertible_v>; - case ref_types::const_lvalue: - return std::is_convertible_v>; - case ref_types::rvalue: - return std::is_convertible_v>; - case ref_types::const_rvalue: - return std::is_convertible_v>; - } - return false; - }; - - if ( is_a(to_type, from_type) && is_convertible() ) { + if ( is_a(to_type, from_type) && is_convertible_to_ref(type_list{}) ) { return true; } } if constexpr ( !std::is_pointer_v && !std::is_reference_v ) { - const auto is_constructible = [this]() { - switch ( get_ref_type() ) { - case ref_types::lvalue: - return std::is_constructible_v && can_cast_to(); - case ref_types::const_lvalue: - return std::is_constructible_v && can_cast_to(); - case ref_types::rvalue: - return std::is_constructible_v && can_cast_to(); - case ref_types::const_rvalue: - return std::is_constructible_v && can_cast_to(); - } - return false; - }; - - if ( is_a(to_type, from_type) && is_constructible() ) { + if ( is_a(to_type, from_type) && is_constructible_from_type(type_list{}) ) { return true; } } @@ -5461,8 +5486,8 @@ namespace meta_hpp::detail namespace meta_hpp::detail { template < typename To > - // NOLINTNEXTLINE(*-cognitive-complexity) - To uarg::cast() const { + requires(std::is_pointer_v) + [[nodiscard]] To uarg::cast() const { META_HPP_ASSERT(can_cast_to() && "bad argument cast"); using to_raw_type_cv = std::remove_reference_t; @@ -5471,104 +5496,105 @@ namespace meta_hpp::detail const any_type& from_type = get_raw_type(); const any_type& to_type = resolve_type(); - if constexpr ( std::is_pointer_v ) { - if ( to_type.is_pointer() && from_type.is_nullptr() ) { - return static_cast(nullptr); + if ( to_type.is_pointer() && from_type.is_nullptr() ) { + return static_cast(nullptr); + } + + if ( to_type.is_pointer() && from_type.is_array() ) { + const pointer_type& to_type_ptr = to_type.as_pointer(); + const array_type& from_type_array = from_type.as_array(); + + const any_type& to_data_type = to_type_ptr.get_data_type(); + const any_type& from_data_type = from_type_array.get_data_type(); + + if ( to_data_type.is_void() || to_data_type == from_data_type ) { + return static_cast(data_); } - if ( to_type.is_pointer() && from_type.is_array() ) { - const pointer_type& to_type_ptr = to_type.as_pointer(); - const array_type& from_type_array = from_type.as_array(); + 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(); - const any_type& to_data_type = to_type_ptr.get_data_type(); - const any_type& from_data_type = from_type_array.get_data_type(); - - if ( to_data_type.is_void() || to_data_type == from_data_type ) { - return static_cast(data_); - } - - 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_ptr = pointer_upcast(data_, from_data_class, to_data_class); - return static_cast(to_ptr); - } - } - - 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(data_); - - if ( to_data_type.is_void() || to_data_type == from_data_type ) { - return static_cast(*from_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_ptr = pointer_upcast(*from_data_ptr, from_data_class, to_data_class); - return static_cast(to_ptr); - } + void* to_ptr = pointer_upcast(data_, from_data_class, to_data_class); + return static_cast(to_ptr); } } - if constexpr ( std::is_reference_v ) { - if ( to_type == from_type ) { - if constexpr ( std::is_lvalue_reference_v ) { - return *static_cast(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(); - if constexpr ( std::is_rvalue_reference_v ) { - return std::move(*static_cast(data_)); - } + 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(data_); + + if ( to_data_type.is_void() || to_data_type == from_data_type ) { + return static_cast(*from_data_ptr); } - 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(); + 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_ptr = pointer_upcast(data_, from_class, to_class); - - if constexpr ( std::is_lvalue_reference_v ) { - return *static_cast(to_ptr); - } - - if constexpr ( std::is_rvalue_reference_v ) { - return std::move(*static_cast(to_ptr)); - } + void* to_ptr = pointer_upcast(*from_data_ptr, from_data_class, to_data_class); + return static_cast(to_ptr); } } - if constexpr ( !std::is_pointer_v && !std::is_reference_v ) { - if constexpr ( std::is_constructible_v ) { - if ( get_ref_type() == ref_types::lvalue ) { - return To{cast()}; - } - } + META_HPP_THROW("bad argument cast"); + } - if constexpr ( std::is_constructible_v ) { - if ( get_ref_type() == ref_types::const_lvalue ) { - return To{cast()}; - } - } + template < typename To > + requires(!std::is_pointer_v) + [[nodiscard]] To uarg::cast() const { + META_HPP_ASSERT(can_cast_to() && "bad argument cast"); - if constexpr ( std::is_constructible_v ) { - if ( get_ref_type() == ref_types::rvalue ) { - return To{cast()}; - } - } + using to_raw_type_cv = std::remove_reference_t; + using to_raw_type = std::remove_cv_t; - if constexpr ( std::is_constructible_v ) { - if ( get_ref_type() == ref_types::const_rvalue ) { - return To{cast()}; + static_assert( // + !(std::is_reference_v && std::is_pointer_v), + "references to pointers are not supported yet" + ); + + const any_type& from_type = get_raw_type(); + const any_type& to_type = resolve_type(); + + void* to_ptr = to_type == from_type // + ? data_ + : pointer_upcast(data_, from_type.as_class(), to_type.as_class()); + + if constexpr ( std::is_lvalue_reference_v ) { + return *static_cast(to_ptr); + } + + if constexpr ( std::is_rvalue_reference_v ) { + return std::move(*static_cast(to_ptr)); + } + + if constexpr ( !std::is_reference_v ) { + switch ( get_ref_type() ) { + case ref_types::lvalue: + if constexpr ( std::is_constructible_v ) { + return To{*static_cast(to_ptr)}; } + break; + case ref_types::const_lvalue: + if constexpr ( std::is_constructible_v ) { + return To{*static_cast(to_ptr)}; + } + break; + case ref_types::rvalue: + if constexpr ( std::is_constructible_v ) { + return To{std::move(*static_cast(to_ptr))}; + } + break; + case ref_types::const_rvalue: + if constexpr ( std::is_constructible_v ) { + return To{std::move(*static_cast(to_ptr))}; + } + break; } } diff --git a/headers/meta.hpp/meta_detail/value_utilities/uarg.hpp b/headers/meta.hpp/meta_detail/value_utilities/uarg.hpp index b96fd6b..3818691 100644 --- a/headers/meta.hpp/meta_detail/value_utilities/uarg.hpp +++ b/headers/meta.hpp/meta_detail/value_utilities/uarg.hpp @@ -82,6 +82,11 @@ namespace meta_hpp::detail } template < typename To > + requires(std::is_pointer_v) + [[nodiscard]] bool can_cast_to() const noexcept; + + template < typename To > + requires(!std::is_pointer_v) [[nodiscard]] bool can_cast_to() const noexcept; private: @@ -117,6 +122,11 @@ namespace meta_hpp::detail , data_{const_cast*>(std::addressof(v))} {} template < typename To > + requires(std::is_pointer_v) + [[nodiscard]] To cast() const; + + template < typename To > + requires(!std::is_pointer_v) [[nodiscard]] To cast() const; private: @@ -127,8 +137,63 @@ namespace meta_hpp::detail namespace meta_hpp::detail { template < typename To > - // NOLINTNEXTLINE(*-cognitive-complexity) - bool uarg_base::can_cast_to() const noexcept { + requires(std::is_pointer_v) + [[nodiscard]] bool uarg_base::can_cast_to() const noexcept { + using to_raw_type_cv = std::remove_reference_t; + using to_raw_type = std::remove_cv_t; + + const any_type& from_type = get_raw_type(); + const any_type& to_type = resolve_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())); + }; + + if ( from_type.is_nullptr() && to_type.is_pointer() ) { + return true; + } + + if ( to_type.is_pointer() && from_type.is_array() ) { + 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); + + const array_type& from_type_array = from_type.as_array(); + const bool from_type_array_readonly = is_ref_const(); + + const any_type& to_data_type = to_type_ptr.get_data_type(); + const any_type& from_data_type = from_type_array.get_data_type(); + + if ( to_type_ptr_readonly >= from_type_array_readonly ) { + if ( to_data_type.is_void() || is_a(to_data_type, from_data_type) ) { + return true; + } + } + } + + 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); + + 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 ( to_type_ptr_readonly >= from_type_ptr_readonly ) { + if ( to_data_type.is_void() || is_a(to_data_type, from_data_type) ) { + return true; + } + } + } + + return false; + } + + template < typename To > + requires(!std::is_pointer_v) + [[nodiscard]] bool uarg_base::can_cast_to() const noexcept { using to_raw_type_cv = std::remove_reference_t; using to_raw_type = std::remove_cv_t; @@ -145,82 +210,42 @@ namespace meta_hpp::detail || (base.is_class() && derived.is_class() && base.as_class().is_base_of(derived.as_class())); }; - if constexpr ( std::is_pointer_v ) { - if ( to_type.is_pointer() && from_type.is_nullptr() ) { - return true; + const auto is_convertible_to_ref = [this](type_list) { + switch ( get_ref_type() ) { + case ref_types::lvalue: + return std::is_convertible_v>; + case ref_types::const_lvalue: + return std::is_convertible_v>; + case ref_types::rvalue: + return std::is_convertible_v>; + case ref_types::const_rvalue: + return std::is_convertible_v>; } + return false; + }; - if ( to_type.is_pointer() && from_type.is_array() ) { - 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); - - const array_type& from_type_array = from_type.as_array(); - const bool from_type_array_readonly = is_ref_const(); - - const any_type& to_data_type = to_type_ptr.get_data_type(); - const any_type& from_data_type = from_type_array.get_data_type(); - - if ( to_type_ptr_readonly >= from_type_array_readonly ) { - if ( to_data_type.is_void() || is_a(to_data_type, from_data_type) ) { - return true; - } - } + const auto is_constructible_from_type = [this, &is_convertible_to_ref](type_list) { + switch ( get_ref_type() ) { + case ref_types::lvalue: + return std::is_constructible_v && is_convertible_to_ref(type_list{}); + case ref_types::const_lvalue: + return std::is_constructible_v && is_convertible_to_ref(type_list{}); + case ref_types::rvalue: + return std::is_constructible_v && is_convertible_to_ref(type_list{}); + case ref_types::const_rvalue: + return std::is_constructible_v && is_convertible_to_ref(type_list{}); } - - 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); - - 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 ( to_type_ptr_readonly >= from_type_ptr_readonly ) { - if ( to_data_type.is_void() || is_a(to_data_type, from_data_type) ) { - return true; - } - } - } - } + return false; + }; if constexpr ( std::is_reference_v ) { - const auto is_convertible = [this]() { - switch ( get_ref_type() ) { - case ref_types::lvalue: - return std::is_convertible_v>; - case ref_types::const_lvalue: - return std::is_convertible_v>; - case ref_types::rvalue: - return std::is_convertible_v>; - case ref_types::const_rvalue: - return std::is_convertible_v>; - } - return false; - }; - - if ( is_a(to_type, from_type) && is_convertible() ) { + if ( is_a(to_type, from_type) && is_convertible_to_ref(type_list{}) ) { return true; } } if constexpr ( !std::is_pointer_v && !std::is_reference_v ) { - const auto is_constructible = [this]() { - switch ( get_ref_type() ) { - case ref_types::lvalue: - return std::is_constructible_v && can_cast_to(); - case ref_types::const_lvalue: - return std::is_constructible_v && can_cast_to(); - case ref_types::rvalue: - return std::is_constructible_v && can_cast_to(); - case ref_types::const_rvalue: - return std::is_constructible_v && can_cast_to(); - } - return false; - }; - - if ( is_a(to_type, from_type) && is_constructible() ) { + if ( is_a(to_type, from_type) && is_constructible_from_type(type_list{}) ) { return true; } } @@ -232,8 +257,8 @@ namespace meta_hpp::detail namespace meta_hpp::detail { template < typename To > - // NOLINTNEXTLINE(*-cognitive-complexity) - To uarg::cast() const { + requires(std::is_pointer_v) + [[nodiscard]] To uarg::cast() const { META_HPP_ASSERT(can_cast_to() && "bad argument cast"); using to_raw_type_cv = std::remove_reference_t; @@ -242,104 +267,105 @@ namespace meta_hpp::detail const any_type& from_type = get_raw_type(); const any_type& to_type = resolve_type(); - if constexpr ( std::is_pointer_v ) { - if ( to_type.is_pointer() && from_type.is_nullptr() ) { - return static_cast(nullptr); + if ( to_type.is_pointer() && from_type.is_nullptr() ) { + return static_cast(nullptr); + } + + if ( to_type.is_pointer() && from_type.is_array() ) { + const pointer_type& to_type_ptr = to_type.as_pointer(); + const array_type& from_type_array = from_type.as_array(); + + const any_type& to_data_type = to_type_ptr.get_data_type(); + const any_type& from_data_type = from_type_array.get_data_type(); + + if ( to_data_type.is_void() || to_data_type == from_data_type ) { + return static_cast(data_); } - if ( to_type.is_pointer() && from_type.is_array() ) { - const pointer_type& to_type_ptr = to_type.as_pointer(); - const array_type& from_type_array = from_type.as_array(); + 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(); - const any_type& to_data_type = to_type_ptr.get_data_type(); - const any_type& from_data_type = from_type_array.get_data_type(); - - if ( to_data_type.is_void() || to_data_type == from_data_type ) { - return static_cast(data_); - } - - 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_ptr = pointer_upcast(data_, from_data_class, to_data_class); - return static_cast(to_ptr); - } - } - - 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(data_); - - if ( to_data_type.is_void() || to_data_type == from_data_type ) { - return static_cast(*from_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_ptr = pointer_upcast(*from_data_ptr, from_data_class, to_data_class); - return static_cast(to_ptr); - } + void* to_ptr = pointer_upcast(data_, from_data_class, to_data_class); + return static_cast(to_ptr); } } - if constexpr ( std::is_reference_v ) { - if ( to_type == from_type ) { - if constexpr ( std::is_lvalue_reference_v ) { - return *static_cast(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(); - if constexpr ( std::is_rvalue_reference_v ) { - return std::move(*static_cast(data_)); - } + 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(data_); + + if ( to_data_type.is_void() || to_data_type == from_data_type ) { + return static_cast(*from_data_ptr); } - 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(); + 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_ptr = pointer_upcast(data_, from_class, to_class); - - if constexpr ( std::is_lvalue_reference_v ) { - return *static_cast(to_ptr); - } - - if constexpr ( std::is_rvalue_reference_v ) { - return std::move(*static_cast(to_ptr)); - } + void* to_ptr = pointer_upcast(*from_data_ptr, from_data_class, to_data_class); + return static_cast(to_ptr); } } - if constexpr ( !std::is_pointer_v && !std::is_reference_v ) { - if constexpr ( std::is_constructible_v ) { - if ( get_ref_type() == ref_types::lvalue ) { - return To{cast()}; - } - } + META_HPP_THROW("bad argument cast"); + } - if constexpr ( std::is_constructible_v ) { - if ( get_ref_type() == ref_types::const_lvalue ) { - return To{cast()}; - } - } + template < typename To > + requires(!std::is_pointer_v) + [[nodiscard]] To uarg::cast() const { + META_HPP_ASSERT(can_cast_to() && "bad argument cast"); - if constexpr ( std::is_constructible_v ) { - if ( get_ref_type() == ref_types::rvalue ) { - return To{cast()}; - } - } + using to_raw_type_cv = std::remove_reference_t; + using to_raw_type = std::remove_cv_t; - if constexpr ( std::is_constructible_v ) { - if ( get_ref_type() == ref_types::const_rvalue ) { - return To{cast()}; + static_assert( // + !(std::is_reference_v && std::is_pointer_v), + "references to pointers are not supported yet" + ); + + const any_type& from_type = get_raw_type(); + const any_type& to_type = resolve_type(); + + void* to_ptr = to_type == from_type // + ? data_ + : pointer_upcast(data_, from_type.as_class(), to_type.as_class()); + + if constexpr ( std::is_lvalue_reference_v ) { + return *static_cast(to_ptr); + } + + if constexpr ( std::is_rvalue_reference_v ) { + return std::move(*static_cast(to_ptr)); + } + + if constexpr ( !std::is_reference_v ) { + switch ( get_ref_type() ) { + case ref_types::lvalue: + if constexpr ( std::is_constructible_v ) { + return To{*static_cast(to_ptr)}; } + break; + case ref_types::const_lvalue: + if constexpr ( std::is_constructible_v ) { + return To{*static_cast(to_ptr)}; + } + break; + case ref_types::rvalue: + if constexpr ( std::is_constructible_v ) { + return To{std::move(*static_cast(to_ptr))}; + } + break; + case ref_types::const_rvalue: + if constexpr ( std::is_constructible_v ) { + return To{std::move(*static_cast(to_ptr))}; + } + break; } }