mirror of
https://github.com/BlackMATov/meta.hpp.git
synced 2025-12-13 11:17:06 +07:00
first version of ucast
This commit is contained in:
@@ -63,6 +63,60 @@
|
||||
# define META_HPP_PP_CAT_I(x, y) x##y
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# define META_HPP_MSVC
|
||||
#elif defined(__clang__)
|
||||
# define META_HPP_CLANG
|
||||
#elif defined(__GNUC__)
|
||||
# define META_HPP_GCC
|
||||
#endif
|
||||
|
||||
#if defined(META_HPP_MSVC)
|
||||
# define META_HPP_MSVC_IGNORE_WARNING(w) __pragma(warning(disable : w))
|
||||
# define META_HPP_MSVC_IGNORE_WARNINGS_PUSH() __pragma(warning(push))
|
||||
# define META_HPP_MSVC_IGNORE_WARNINGS_POP() __pragma(warning(pop))
|
||||
#else
|
||||
# define META_HPP_MSVC_IGNORE_WARNING(w)
|
||||
# define META_HPP_MSVC_IGNORE_WARNINGS_PUSH()
|
||||
# define META_HPP_MSVC_IGNORE_WARNINGS_POP()
|
||||
#endif
|
||||
|
||||
#if defined(META_HPP_CLANG)
|
||||
# define META_HPP_CLANG_PRAGMA_TO_STR(x) _Pragma(#x)
|
||||
# define META_HPP_CLANG_IGNORE_WARNING(w) META_HPP_CLANG_PRAGMA_TO_STR(clang diagnostic ignored w)
|
||||
# define META_HPP_CLANG_IGNORE_WARNINGS_PUSH() _Pragma("clang diagnostic push")
|
||||
# define META_HPP_CLANG_IGNORE_WARNINGS_POP() _Pragma("clang diagnostic pop")
|
||||
#else
|
||||
# define META_HPP_CLANG_PRAGMA_TO_STR(x)
|
||||
# define META_HPP_CLANG_IGNORE_WARNING(w)
|
||||
# define META_HPP_CLANG_IGNORE_WARNINGS_PUSH()
|
||||
# define META_HPP_CLANG_IGNORE_WARNINGS_POP()
|
||||
#endif
|
||||
|
||||
#if defined(META_HPP_GCC)
|
||||
# define META_HPP_GCC_PRAGMA_TO_STR(x) _Pragma(#x)
|
||||
# define META_HPP_GCC_IGNORE_WARNING(w) META_HPP_GCC_PRAGMA_TO_STR(GCC diagnostic ignored w)
|
||||
# define META_HPP_GCC_IGNORE_WARNINGS_PUSH() _Pragma("GCC diagnostic push")
|
||||
# define META_HPP_GCC_IGNORE_WARNINGS_POP() _Pragma("GCC diagnostic pop")
|
||||
#else
|
||||
# define META_HPP_GCC_PRAGMA_TO_STR(x)
|
||||
# define META_HPP_GCC_IGNORE_WARNING(w)
|
||||
# define META_HPP_GCC_IGNORE_WARNINGS_PUSH()
|
||||
# define META_HPP_GCC_IGNORE_WARNINGS_POP()
|
||||
#endif
|
||||
|
||||
#define META_HPP_IGNORE_OVERRIDE_WARNINGS_PUSH() \
|
||||
META_HPP_MSVC_IGNORE_WARNINGS_PUSH() \
|
||||
META_HPP_CLANG_IGNORE_WARNINGS_PUSH() \
|
||||
META_HPP_GCC_IGNORE_WARNINGS_PUSH() \
|
||||
META_HPP_CLANG_IGNORE_WARNING("-Winconsistent-missing-override") \
|
||||
META_HPP_CLANG_IGNORE_WARNING("-Wsuggest-override")
|
||||
|
||||
#define META_HPP_IGNORE_OVERRIDE_WARNINGS_POP() \
|
||||
META_HPP_GCC_IGNORE_WARNINGS_POP() \
|
||||
META_HPP_CLANG_IGNORE_WARNINGS_POP() \
|
||||
META_HPP_MSVC_IGNORE_WARNINGS_POP()\
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
template < typename Enum >
|
||||
@@ -458,6 +512,8 @@ namespace meta_hpp::detail
|
||||
enum class error_code {
|
||||
no_error,
|
||||
|
||||
bad_cast,
|
||||
|
||||
bad_const_access,
|
||||
bad_uvalue_access,
|
||||
|
||||
@@ -473,6 +529,8 @@ namespace meta_hpp::detail
|
||||
switch ( error ) {
|
||||
case error_code::no_error:
|
||||
return "no error";
|
||||
case error_code::bad_cast:
|
||||
return "bad cast";
|
||||
case error_code::bad_const_access:
|
||||
return "bad const access";
|
||||
case error_code::bad_uvalue_access:
|
||||
@@ -4285,67 +4343,67 @@ namespace meta_hpp::detail
|
||||
public:
|
||||
template < array_kind Array >
|
||||
[[nodiscard]] array_type resolve_array_type() {
|
||||
return array_type{resolve_array_type_data<Array>()};
|
||||
return array_type{resolve_array_type_data<std::remove_cv_t<Array>>()};
|
||||
}
|
||||
|
||||
template < class_kind Class >
|
||||
[[nodiscard]] class_type resolve_class_type() {
|
||||
return class_type{resolve_class_type_data<Class>()};
|
||||
return class_type{resolve_class_type_data<std::remove_cv_t<Class>>()};
|
||||
}
|
||||
|
||||
template < class_kind Class, typename... Args >
|
||||
[[nodiscard]] constructor_type resolve_constructor_type() {
|
||||
return constructor_type{resolve_constructor_type_data<Class, Args...>()};
|
||||
return constructor_type{resolve_constructor_type_data<std::remove_cv_t<Class>, Args...>()};
|
||||
}
|
||||
|
||||
template < class_kind Class >
|
||||
[[nodiscard]] destructor_type resolve_destructor_type() {
|
||||
return destructor_type{resolve_destructor_type_data<Class>()};
|
||||
return destructor_type{resolve_destructor_type_data<std::remove_cv_t<Class>>()};
|
||||
}
|
||||
|
||||
template < enum_kind Enum >
|
||||
[[nodiscard]] enum_type resolve_enum_type() {
|
||||
return enum_type{resolve_enum_type_data<Enum>()};
|
||||
return enum_type{resolve_enum_type_data<std::remove_cv_t<Enum>>()};
|
||||
}
|
||||
|
||||
template < function_pointer_kind Function >
|
||||
[[nodiscard]] function_type resolve_function_type() {
|
||||
return function_type{resolve_function_type_data<Function>()};
|
||||
return function_type{resolve_function_type_data<std::remove_cv_t<Function>>()};
|
||||
}
|
||||
|
||||
template < member_pointer_kind Member >
|
||||
[[nodiscard]] member_type resolve_member_type() {
|
||||
return member_type{resolve_member_type_data<Member>()};
|
||||
return member_type{resolve_member_type_data<std::remove_cv_t<Member>>()};
|
||||
}
|
||||
|
||||
template < method_pointer_kind Method >
|
||||
[[nodiscard]] method_type resolve_method_type() {
|
||||
return method_type{resolve_method_type_data<Method>()};
|
||||
return method_type{resolve_method_type_data<std::remove_cv_t<Method>>()};
|
||||
}
|
||||
|
||||
template < nullptr_kind Nullptr >
|
||||
[[nodiscard]] nullptr_type resolve_nullptr_type() {
|
||||
return nullptr_type{resolve_nullptr_type_data<Nullptr>()};
|
||||
return nullptr_type{resolve_nullptr_type_data<std::remove_cv_t<Nullptr>>()};
|
||||
}
|
||||
|
||||
template < number_kind Number >
|
||||
[[nodiscard]] number_type resolve_number_type() {
|
||||
return number_type{resolve_number_type_data<Number>()};
|
||||
return number_type{resolve_number_type_data<std::remove_cv_t<Number>>()};
|
||||
}
|
||||
|
||||
template < pointer_kind Pointer >
|
||||
[[nodiscard]] pointer_type resolve_pointer_type() {
|
||||
return pointer_type{resolve_pointer_type_data<Pointer>()};
|
||||
return pointer_type{resolve_pointer_type_data<std::remove_cv_t<Pointer>>()};
|
||||
}
|
||||
|
||||
template < reference_kind Reference >
|
||||
[[nodiscard]] reference_type resolve_reference_type() {
|
||||
return reference_type{resolve_reference_type_data<Reference>()};
|
||||
return reference_type{resolve_reference_type_data<std::remove_cv_t<Reference>>()};
|
||||
}
|
||||
|
||||
template < void_kind Void >
|
||||
[[nodiscard]] void_type resolve_void_type() {
|
||||
return void_type{resolve_void_type_data<Void>()};
|
||||
return void_type{resolve_void_type_data<std::remove_cv_t<Void>>()};
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -9043,6 +9101,122 @@ namespace meta_hpp::detail
|
||||
: type_data_base{type_id{type_list<void_tag<Void>>{}}, type_kind::void_} {}
|
||||
}
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
template <
|
||||
typename To,
|
||||
typename From,
|
||||
typename ToDT = std::remove_pointer_t<To>,
|
||||
typename FromDT = std::remove_pointer_t<From> >
|
||||
concept pointer_ucast_kind //
|
||||
= (std::is_pointer_v<From> && std::is_class_v<FromDT>) //
|
||||
&& (std::is_pointer_v<To> && (std::is_class_v<ToDT> || std::is_void_v<ToDT>)) //
|
||||
&& (!std::is_const_v<FromDT> || std::is_const_v<ToDT>) //
|
||||
&& (!std::is_volatile_v<FromDT> || std::is_volatile_v<ToDT>); //
|
||||
|
||||
template <
|
||||
typename To,
|
||||
typename From,
|
||||
typename ToDT = std::remove_reference_t<To>,
|
||||
typename FromDT = std::remove_reference_t<From> >
|
||||
concept reference_ucast_kind //
|
||||
= (std::is_reference_v<From> && std::is_class_v<FromDT>) //
|
||||
&& (std::is_reference_v<To> && std::is_class_v<ToDT>) //
|
||||
&& (!std::is_const_v<FromDT> || std::is_const_v<ToDT>) //
|
||||
&& (!std::is_volatile_v<FromDT> || std::is_volatile_v<ToDT>); //
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
{
|
||||
template < typename To, typename From >
|
||||
requires detail::pointer_ucast_kind<To, From>
|
||||
To ucast(From from);
|
||||
|
||||
template < typename To, typename From >
|
||||
requires detail::reference_ucast_kind<To, From>
|
||||
To ucast(From&& from);
|
||||
}
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
struct polymorphic_meta_info {
|
||||
const void* ptr{};
|
||||
class_type type{};
|
||||
};
|
||||
|
||||
template < typename T >
|
||||
concept check_polymorphic_cast_support //
|
||||
= requires(type_registry& r, const T& v) {
|
||||
{ v.get_most_derived_polymorphic_meta_info(r) } -> std::convertible_to<polymorphic_meta_info>;
|
||||
};
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
{
|
||||
template < typename To, typename From >
|
||||
requires detail::pointer_ucast_kind<To, From>
|
||||
To ucast(From from) {
|
||||
using from_data_type = std::remove_pointer_t<From>;
|
||||
using to_data_type = std::remove_pointer_t<To>;
|
||||
|
||||
static_assert(
|
||||
detail::check_polymorphic_cast_support<from_data_type>,
|
||||
"The type doesn't support ucasts. Use the META_HPP_ENABLE_POLYMORPHIC_CAST macro to fix it."
|
||||
);
|
||||
|
||||
if ( from == nullptr ) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if constexpr ( std::is_same_v<std::remove_cv_t<from_data_type>, std::remove_cv_t<to_data_type>> ) {
|
||||
return from;
|
||||
}
|
||||
|
||||
detail::type_registry& registry{detail::type_registry::instance()};
|
||||
const detail::polymorphic_meta_info& meta_info{from->get_most_derived_polymorphic_meta_info(registry)};
|
||||
|
||||
// NOLINTNEXTLINE(*-const-cast)
|
||||
void* most_derived_object_ptr = const_cast<void*>(meta_info.ptr);
|
||||
|
||||
if constexpr ( std::is_void_v<std::remove_cv_t<to_data_type>> ) {
|
||||
return most_derived_object_ptr;
|
||||
} else {
|
||||
const class_type& to_class_type = registry.resolve_class_type<to_data_type>();
|
||||
return static_cast<To>(detail::pointer_upcast(most_derived_object_ptr, meta_info.type, to_class_type));
|
||||
}
|
||||
}
|
||||
|
||||
template < typename To, typename From >
|
||||
requires detail::reference_ucast_kind<To, From>
|
||||
To ucast(From&& from) {
|
||||
using from_data_type = std::remove_reference_t<From>;
|
||||
using to_data_type = std::remove_reference_t<To>;
|
||||
|
||||
static_assert(
|
||||
detail::check_polymorphic_cast_support<from_data_type>,
|
||||
"The type doesn't support ucasts. Use the META_HPP_ENABLE_POLYMORPHIC_CAST macro to fix it."
|
||||
);
|
||||
|
||||
if ( to_data_type* ptr = ucast<to_data_type*>(std::addressof(from)) ) {
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
throw_exception(error_code::bad_cast);
|
||||
}
|
||||
}
|
||||
|
||||
#define META_HPP_ENABLE_POLYMORPHIC_CAST() \
|
||||
public: \
|
||||
META_HPP_IGNORE_OVERRIDE_WARNINGS_PUSH() \
|
||||
virtual ::meta_hpp::detail::polymorphic_meta_info get_most_derived_polymorphic_meta_info( \
|
||||
::meta_hpp::detail::type_registry& registry \
|
||||
) const { \
|
||||
using self_type = std::remove_cvref_t<decltype(*this)>; \
|
||||
return ::meta_hpp::detail::polymorphic_meta_info{.ptr = this, .type = registry.resolve_class_type<self_type>()}; \
|
||||
} \
|
||||
META_HPP_IGNORE_OVERRIDE_WARNINGS_POP() \
|
||||
private:
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
template < typename T >
|
||||
|
||||
219
develop/unbench/dynamic_cast_bench.cpp
Normal file
219
develop/unbench/dynamic_cast_bench.cpp
Normal file
@@ -0,0 +1,219 @@
|
||||
/*******************************************************************************
|
||||
* This file is part of the "https://github.com/blackmatov/meta.hpp"
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.md
|
||||
* Copyright (C) 2021-2023, by Matvey Cherevko (blackmatov@gmail.com)
|
||||
******************************************************************************/
|
||||
|
||||
#include <meta.hpp/meta_all.hpp>
|
||||
#include <vmath.hpp/vmath_all.hpp>
|
||||
|
||||
#include <rttr/type>
|
||||
#include <rttr/registration>
|
||||
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
namespace meta = meta_hpp;
|
||||
namespace vmath = vmath_hpp;
|
||||
|
||||
struct base1 {
|
||||
unsigned b1{1};
|
||||
|
||||
base1() = default;
|
||||
virtual ~base1() = default;
|
||||
|
||||
base1(const base1&) = default;
|
||||
base1& operator=(const base1&) = default;
|
||||
|
||||
RTTR_ENABLE()
|
||||
META_HPP_ENABLE_POLYMORPHIC_CAST()
|
||||
};
|
||||
|
||||
struct base2 : base1 {
|
||||
unsigned b2{2};
|
||||
RTTR_ENABLE(base1)
|
||||
META_HPP_ENABLE_POLYMORPHIC_CAST()
|
||||
};
|
||||
|
||||
struct base3 : base2 {
|
||||
unsigned b3{3};
|
||||
RTTR_ENABLE(base2)
|
||||
META_HPP_ENABLE_POLYMORPHIC_CAST()
|
||||
};
|
||||
|
||||
struct base4 : base3 {
|
||||
unsigned b4{4};
|
||||
RTTR_ENABLE(base3)
|
||||
META_HPP_ENABLE_POLYMORPHIC_CAST()
|
||||
};
|
||||
|
||||
base4* dynamic_cast_1(base1* b1) {
|
||||
return dynamic_cast<base4*>(b1);
|
||||
}
|
||||
|
||||
base4* dynamic_cast_2(base2* b2) {
|
||||
return dynamic_cast<base4*>(b2);
|
||||
}
|
||||
|
||||
base4* dynamic_cast_3(base3* b3) {
|
||||
return dynamic_cast<base4*>(b3);
|
||||
}
|
||||
|
||||
base4* dynamic_cast_4(base4* b4) {
|
||||
return dynamic_cast<base4*>(b4);
|
||||
}
|
||||
|
||||
const bool registered = [](){
|
||||
meta::class_<base1>();
|
||||
meta::class_<base2>().base_<base1>();
|
||||
meta::class_<base3>().base_<base2>();
|
||||
meta::class_<base4>().base_<base3>();
|
||||
return true;
|
||||
}();
|
||||
}
|
||||
|
||||
//
|
||||
// native
|
||||
//
|
||||
|
||||
namespace
|
||||
{
|
||||
[[maybe_unused]]
|
||||
void dynamic_cast_1(benchmark::State &state) {
|
||||
base4 b4;
|
||||
for ( auto _ : state ) {
|
||||
base4* r = dynamic_cast_1(&b4);
|
||||
benchmark::DoNotOptimize(r);
|
||||
}
|
||||
}
|
||||
|
||||
[[maybe_unused]]
|
||||
void dynamic_cast_2(benchmark::State &state) {
|
||||
base4 b4;
|
||||
for ( auto _ : state ) {
|
||||
base4* r = dynamic_cast_2(&b4);
|
||||
benchmark::DoNotOptimize(r);
|
||||
}
|
||||
}
|
||||
|
||||
[[maybe_unused]]
|
||||
void dynamic_cast_3(benchmark::State &state) {
|
||||
base4 b4;
|
||||
for ( auto _ : state ) {
|
||||
base4* r = dynamic_cast_3(&b4);
|
||||
benchmark::DoNotOptimize(r);
|
||||
}
|
||||
}
|
||||
|
||||
[[maybe_unused]]
|
||||
void dynamic_cast_4(benchmark::State &state) {
|
||||
base4 b4;
|
||||
for ( auto _ : state ) {
|
||||
base4* r = dynamic_cast_4(&b4);
|
||||
benchmark::DoNotOptimize(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// meta
|
||||
//
|
||||
|
||||
namespace
|
||||
{
|
||||
[[maybe_unused]]
|
||||
void meta_dynamic_cast_1(benchmark::State &state) {
|
||||
base4 b4;
|
||||
for ( auto _ : state ) {
|
||||
base4* r = meta::ucast<base4*>(static_cast<base1*>(&b4));
|
||||
benchmark::DoNotOptimize(r);
|
||||
}
|
||||
}
|
||||
|
||||
[[maybe_unused]]
|
||||
void meta_dynamic_cast_2(benchmark::State &state) {
|
||||
base4 b4;
|
||||
for ( auto _ : state ) {
|
||||
base4* r = meta::ucast<base4*>(static_cast<base2*>(&b4));
|
||||
benchmark::DoNotOptimize(r);
|
||||
}
|
||||
}
|
||||
|
||||
[[maybe_unused]]
|
||||
void meta_dynamic_cast_3(benchmark::State &state) {
|
||||
base4 b4;
|
||||
for ( auto _ : state ) {
|
||||
base4* r = meta::ucast<base4*>(static_cast<base3*>(&b4));
|
||||
benchmark::DoNotOptimize(r);
|
||||
}
|
||||
}
|
||||
|
||||
[[maybe_unused]]
|
||||
void meta_dynamic_cast_4(benchmark::State &state) {
|
||||
base4 b4;
|
||||
for ( auto _ : state ) {
|
||||
base4* r = meta::ucast<base4*>(static_cast<base4*>(&b4));
|
||||
benchmark::DoNotOptimize(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// rttr
|
||||
//
|
||||
|
||||
namespace
|
||||
{
|
||||
[[maybe_unused]]
|
||||
void rttr_dynamic_cast_1(benchmark::State &state) {
|
||||
base4 b4;
|
||||
for ( auto _ : state ) {
|
||||
base4* r = rttr::rttr_cast<base4*>(static_cast<base1*>(&b4));
|
||||
benchmark::DoNotOptimize(r);
|
||||
}
|
||||
}
|
||||
|
||||
[[maybe_unused]]
|
||||
void rttr_dynamic_cast_2(benchmark::State &state) {
|
||||
base4 b4;
|
||||
for ( auto _ : state ) {
|
||||
base4* r = rttr::rttr_cast<base4*>(static_cast<base2*>(&b4));
|
||||
benchmark::DoNotOptimize(r);
|
||||
}
|
||||
}
|
||||
|
||||
[[maybe_unused]]
|
||||
void rttr_dynamic_cast_3(benchmark::State &state) {
|
||||
base4 b4;
|
||||
for ( auto _ : state ) {
|
||||
base4* r = rttr::rttr_cast<base4*>(static_cast<base3*>(&b4));
|
||||
benchmark::DoNotOptimize(r);
|
||||
}
|
||||
}
|
||||
|
||||
[[maybe_unused]]
|
||||
void rttr_dynamic_cast_4(benchmark::State &state) {
|
||||
base4 b4;
|
||||
for ( auto _ : state ) {
|
||||
base4* r = rttr::rttr_cast<base4*>(static_cast<base4*>(&b4));
|
||||
benchmark::DoNotOptimize(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK(dynamic_cast_1);
|
||||
BENCHMARK(meta_dynamic_cast_1);
|
||||
BENCHMARK(rttr_dynamic_cast_1);
|
||||
|
||||
BENCHMARK(dynamic_cast_2);
|
||||
BENCHMARK(meta_dynamic_cast_2);
|
||||
BENCHMARK(rttr_dynamic_cast_2);
|
||||
|
||||
BENCHMARK(dynamic_cast_3);
|
||||
BENCHMARK(meta_dynamic_cast_3);
|
||||
BENCHMARK(rttr_dynamic_cast_3);
|
||||
|
||||
BENCHMARK(dynamic_cast_4);
|
||||
BENCHMARK(meta_dynamic_cast_4);
|
||||
BENCHMARK(rttr_dynamic_cast_4);
|
||||
370
develop/untests/meta_utilities/cast_tests.cpp
Normal file
370
develop/untests/meta_utilities/cast_tests.cpp
Normal file
@@ -0,0 +1,370 @@
|
||||
/*******************************************************************************
|
||||
* This file is part of the "https://github.com/blackmatov/meta.hpp"
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.md
|
||||
* Copyright (C) 2021-2023, by Matvey Cherevko (blackmatov@gmail.com)
|
||||
******************************************************************************/
|
||||
|
||||
#include <meta.hpp/meta_all.hpp>
|
||||
#include <doctest/doctest.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
struct A1 {
|
||||
A1() = default;
|
||||
A1(const A1&) = default;
|
||||
virtual ~A1() = default;
|
||||
char a{'a'};
|
||||
META_HPP_ENABLE_POLYMORPHIC_CAST()
|
||||
};
|
||||
|
||||
struct B1 : A1 {
|
||||
B1() = default;
|
||||
B1(const B1&) = default;
|
||||
char b{'b'};
|
||||
META_HPP_ENABLE_POLYMORPHIC_CAST()
|
||||
};
|
||||
|
||||
struct C1 : B1 {
|
||||
C1() = default;
|
||||
C1(const C1&) = default;
|
||||
char c{'c'};
|
||||
META_HPP_ENABLE_POLYMORPHIC_CAST()
|
||||
};
|
||||
|
||||
// A1 <- B1 <- C1
|
||||
|
||||
struct A2 {
|
||||
A2() = default;
|
||||
A2(const A2&) = default;
|
||||
virtual ~A2() = default;
|
||||
char a{'a'};
|
||||
META_HPP_ENABLE_POLYMORPHIC_CAST()
|
||||
};
|
||||
|
||||
struct B2 : virtual A2 {
|
||||
B2() = default;
|
||||
B2(const B2&) = default;
|
||||
char b{'b'};
|
||||
META_HPP_ENABLE_POLYMORPHIC_CAST()
|
||||
};
|
||||
|
||||
struct C2 : virtual A2 {
|
||||
C2() = default;
|
||||
C2(const C2&) = default;
|
||||
char c{'c'};
|
||||
META_HPP_ENABLE_POLYMORPHIC_CAST()
|
||||
};
|
||||
|
||||
|
||||
struct D2 {
|
||||
D2() = default;
|
||||
D2(const D2&) = default;
|
||||
virtual ~D2() = default;
|
||||
char d{'d'};
|
||||
META_HPP_ENABLE_POLYMORPHIC_CAST()
|
||||
};
|
||||
|
||||
struct E2 : D2 {
|
||||
E2() = default;
|
||||
E2(const E2&) = default;
|
||||
char e{'e'};
|
||||
META_HPP_ENABLE_POLYMORPHIC_CAST()
|
||||
};
|
||||
|
||||
struct F2 : B2, C2, E2 {
|
||||
F2() = default;
|
||||
F2(const F2&) = default;
|
||||
char f{'f'};
|
||||
META_HPP_ENABLE_POLYMORPHIC_CAST()
|
||||
};
|
||||
|
||||
|
||||
// A2 <= B2
|
||||
// <-
|
||||
// A2 <= C2 F2
|
||||
// <-
|
||||
// D2 <- E2
|
||||
|
||||
namespace meta = meta_hpp;
|
||||
|
||||
template < meta::detail::class_kind From, meta::detail::class_kind To, typename Value >
|
||||
void check_casts_impl(Value& value) {
|
||||
using from_void_cv = meta::detail::add_cv_t<From, void>;
|
||||
from_void_cv* from_void_ptr = dynamic_cast<from_void_cv*>(std::addressof(value));
|
||||
REQUIRE(from_void_ptr == meta::ucast<from_void_cv*>(std::addressof(value)));
|
||||
|
||||
From* from_ptr = dynamic_cast<From*>(std::addressof(value));
|
||||
REQUIRE(from_ptr == meta::ucast<From*>(std::addressof(value)));
|
||||
|
||||
using to_void_cv = meta::detail::add_cv_t<To, void>;
|
||||
to_void_cv* to_void_ptr = dynamic_cast<to_void_cv*>(from_ptr);
|
||||
REQUIRE(to_void_ptr == meta::ucast<to_void_cv*>(from_ptr));
|
||||
|
||||
To* to_ptr = dynamic_cast<To*>(from_ptr);
|
||||
REQUIRE(to_ptr == meta::ucast<To*>(from_ptr));
|
||||
|
||||
if ( from_ptr ) {
|
||||
if ( to_ptr ) {
|
||||
REQUIRE(to_ptr == std::addressof(meta::ucast<To&>(*from_ptr)));
|
||||
} else {
|
||||
REQUIRE_THROWS(meta::ucast<To&>(*from_ptr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template < meta::detail::class_kind From, meta::detail::class_kind To, typename Value >
|
||||
void check_casts(Value& value) {
|
||||
check_casts_impl<From, To>(value);
|
||||
check_casts_impl<const From, const To>(std::as_const(value));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("meta/meta_utilities/ucast/_") {
|
||||
namespace meta = meta_hpp;
|
||||
|
||||
meta::class_<A1>();
|
||||
meta::class_<B1>().base_<A1>();
|
||||
meta::class_<C1>().base_<B1>();
|
||||
|
||||
meta::class_<A2>();
|
||||
meta::class_<B2>().base_<A2>();
|
||||
meta::class_<C2>().base_<A2>();
|
||||
meta::class_<D2>();
|
||||
meta::class_<E2>().base_<D2>();
|
||||
meta::class_<F2>().base_<B2, C2, E2>();
|
||||
}
|
||||
|
||||
TEST_CASE("meta/meta_utilities/ucast") {
|
||||
namespace meta = meta_hpp;
|
||||
|
||||
SUBCASE("1") {
|
||||
{
|
||||
C1 c;
|
||||
|
||||
check_casts<A1, A1>(c);
|
||||
check_casts<A1, B1>(c);
|
||||
check_casts<A1, C1>(c);
|
||||
|
||||
check_casts<B1, A1>(c);
|
||||
check_casts<B1, B1>(c);
|
||||
check_casts<B1, C1>(c);
|
||||
|
||||
check_casts<C1, A1>(c);
|
||||
check_casts<C1, B1>(c);
|
||||
check_casts<C1, C1>(c);
|
||||
}
|
||||
{
|
||||
B1 b;
|
||||
|
||||
check_casts<A1, A1>(b);
|
||||
check_casts<A1, B1>(b);
|
||||
check_casts<A1, C1>(b);
|
||||
|
||||
check_casts<B1, A1>(b);
|
||||
check_casts<B1, B1>(b);
|
||||
check_casts<B1, C1>(b);
|
||||
|
||||
check_casts<C1, A1>(b);
|
||||
check_casts<C1, B1>(b);
|
||||
check_casts<C1, C1>(b);
|
||||
}
|
||||
{
|
||||
A1 a;
|
||||
|
||||
check_casts<A1, A1>(a);
|
||||
check_casts<A1, B1>(a);
|
||||
check_casts<A1, C1>(a);
|
||||
|
||||
check_casts<B1, A1>(a);
|
||||
check_casts<B1, B1>(a);
|
||||
check_casts<B1, C1>(a);
|
||||
|
||||
check_casts<C1, A1>(a);
|
||||
check_casts<C1, B1>(a);
|
||||
check_casts<C1, C1>(a);
|
||||
}
|
||||
}
|
||||
|
||||
SUBCASE("2") {
|
||||
{
|
||||
F2 f;
|
||||
|
||||
check_casts<A2, A2>(f);
|
||||
check_casts<A2, B2>(f);
|
||||
check_casts<A2, C2>(f);
|
||||
check_casts<A2, D2>(f);
|
||||
check_casts<A2, E2>(f);
|
||||
check_casts<A2, F2>(f);
|
||||
|
||||
check_casts<B2, A2>(f);
|
||||
check_casts<B2, B2>(f);
|
||||
check_casts<B2, C2>(f);
|
||||
check_casts<B2, D2>(f);
|
||||
check_casts<B2, E2>(f);
|
||||
check_casts<B2, F2>(f);
|
||||
|
||||
check_casts<C2, A2>(f);
|
||||
check_casts<C2, B2>(f);
|
||||
check_casts<C2, C2>(f);
|
||||
check_casts<C2, D2>(f);
|
||||
check_casts<C2, E2>(f);
|
||||
check_casts<C2, F2>(f);
|
||||
|
||||
check_casts<D2, A2>(f);
|
||||
check_casts<D2, B2>(f);
|
||||
check_casts<D2, C2>(f);
|
||||
check_casts<D2, D2>(f);
|
||||
check_casts<D2, E2>(f);
|
||||
check_casts<D2, F2>(f);
|
||||
|
||||
check_casts<E2, A2>(f);
|
||||
check_casts<E2, B2>(f);
|
||||
check_casts<E2, C2>(f);
|
||||
check_casts<E2, D2>(f);
|
||||
check_casts<E2, E2>(f);
|
||||
check_casts<E2, F2>(f);
|
||||
|
||||
check_casts<F2, A2>(f);
|
||||
check_casts<F2, B2>(f);
|
||||
check_casts<F2, C2>(f);
|
||||
check_casts<F2, D2>(f);
|
||||
check_casts<F2, E2>(f);
|
||||
check_casts<F2, F2>(f);
|
||||
}
|
||||
{
|
||||
B2 b;
|
||||
|
||||
check_casts<A2, A2>(b);
|
||||
check_casts<A2, B2>(b);
|
||||
check_casts<A2, C2>(b);
|
||||
check_casts<A2, D2>(b);
|
||||
check_casts<A2, E2>(b);
|
||||
check_casts<A2, F2>(b);
|
||||
|
||||
check_casts<B2, A2>(b);
|
||||
check_casts<B2, B2>(b);
|
||||
check_casts<B2, C2>(b);
|
||||
check_casts<B2, D2>(b);
|
||||
check_casts<B2, E2>(b);
|
||||
check_casts<B2, F2>(b);
|
||||
|
||||
check_casts<C2, A2>(b);
|
||||
check_casts<C2, B2>(b);
|
||||
check_casts<C2, C2>(b);
|
||||
check_casts<C2, D2>(b);
|
||||
check_casts<C2, E2>(b);
|
||||
check_casts<C2, F2>(b);
|
||||
|
||||
check_casts<D2, A2>(b);
|
||||
check_casts<D2, B2>(b);
|
||||
check_casts<D2, C2>(b);
|
||||
check_casts<D2, D2>(b);
|
||||
check_casts<D2, E2>(b);
|
||||
check_casts<D2, F2>(b);
|
||||
|
||||
check_casts<E2, A2>(b);
|
||||
check_casts<E2, B2>(b);
|
||||
check_casts<E2, C2>(b);
|
||||
check_casts<E2, D2>(b);
|
||||
check_casts<E2, E2>(b);
|
||||
check_casts<E2, F2>(b);
|
||||
|
||||
check_casts<F2, A2>(b);
|
||||
check_casts<F2, B2>(b);
|
||||
check_casts<F2, C2>(b);
|
||||
check_casts<F2, D2>(b);
|
||||
check_casts<F2, E2>(b);
|
||||
check_casts<F2, F2>(b);
|
||||
}
|
||||
{
|
||||
E2 e;
|
||||
|
||||
check_casts<A2, A2>(e);
|
||||
check_casts<A2, B2>(e);
|
||||
check_casts<A2, C2>(e);
|
||||
check_casts<A2, D2>(e);
|
||||
check_casts<A2, E2>(e);
|
||||
check_casts<A2, F2>(e);
|
||||
|
||||
check_casts<B2, A2>(e);
|
||||
check_casts<B2, B2>(e);
|
||||
check_casts<B2, C2>(e);
|
||||
check_casts<B2, D2>(e);
|
||||
check_casts<B2, E2>(e);
|
||||
check_casts<B2, F2>(e);
|
||||
|
||||
check_casts<C2, A2>(e);
|
||||
check_casts<C2, B2>(e);
|
||||
check_casts<C2, C2>(e);
|
||||
check_casts<C2, D2>(e);
|
||||
check_casts<C2, E2>(e);
|
||||
check_casts<C2, F2>(e);
|
||||
|
||||
check_casts<D2, A2>(e);
|
||||
check_casts<D2, B2>(e);
|
||||
check_casts<D2, C2>(e);
|
||||
check_casts<D2, D2>(e);
|
||||
check_casts<D2, E2>(e);
|
||||
check_casts<D2, F2>(e);
|
||||
|
||||
check_casts<E2, A2>(e);
|
||||
check_casts<E2, B2>(e);
|
||||
check_casts<E2, C2>(e);
|
||||
check_casts<E2, D2>(e);
|
||||
check_casts<E2, E2>(e);
|
||||
check_casts<E2, F2>(e);
|
||||
|
||||
check_casts<F2, A2>(e);
|
||||
check_casts<F2, B2>(e);
|
||||
check_casts<F2, C2>(e);
|
||||
check_casts<F2, D2>(e);
|
||||
check_casts<F2, E2>(e);
|
||||
check_casts<F2, F2>(e);
|
||||
}
|
||||
{
|
||||
D2 d;
|
||||
|
||||
check_casts<A2, A2>(d);
|
||||
check_casts<A2, B2>(d);
|
||||
check_casts<A2, C2>(d);
|
||||
check_casts<A2, D2>(d);
|
||||
check_casts<A2, E2>(d);
|
||||
check_casts<A2, F2>(d);
|
||||
|
||||
check_casts<B2, A2>(d);
|
||||
check_casts<B2, B2>(d);
|
||||
check_casts<B2, C2>(d);
|
||||
check_casts<B2, D2>(d);
|
||||
check_casts<B2, E2>(d);
|
||||
check_casts<B2, F2>(d);
|
||||
|
||||
check_casts<C2, A2>(d);
|
||||
check_casts<C2, B2>(d);
|
||||
check_casts<C2, C2>(d);
|
||||
check_casts<C2, D2>(d);
|
||||
check_casts<C2, E2>(d);
|
||||
check_casts<C2, F2>(d);
|
||||
|
||||
check_casts<D2, A2>(d);
|
||||
check_casts<D2, B2>(d);
|
||||
check_casts<D2, C2>(d);
|
||||
check_casts<D2, D2>(d);
|
||||
check_casts<D2, E2>(d);
|
||||
check_casts<D2, F2>(d);
|
||||
|
||||
check_casts<E2, A2>(d);
|
||||
check_casts<E2, B2>(d);
|
||||
check_casts<E2, C2>(d);
|
||||
check_casts<E2, D2>(d);
|
||||
check_casts<E2, E2>(d);
|
||||
check_casts<E2, F2>(d);
|
||||
|
||||
check_casts<F2, A2>(d);
|
||||
check_casts<F2, B2>(d);
|
||||
check_casts<F2, C2>(d);
|
||||
check_casts<F2, D2>(d);
|
||||
check_casts<F2, E2>(d);
|
||||
check_casts<F2, F2>(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,6 +65,9 @@
|
||||
#include "meta_types/reference_type.hpp"
|
||||
#include "meta_types/void_type.hpp"
|
||||
|
||||
#include "meta_ucast.hpp"
|
||||
#include "meta_ucast/ucast.hpp"
|
||||
|
||||
#include "meta_uresult.hpp"
|
||||
#include "meta_uresult/uresult.hpp"
|
||||
|
||||
|
||||
@@ -63,3 +63,57 @@
|
||||
# define META_HPP_PP_CAT(x, y) META_HPP_PP_CAT_I(x, y)
|
||||
# define META_HPP_PP_CAT_I(x, y) x##y
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# define META_HPP_MSVC
|
||||
#elif defined(__clang__)
|
||||
# define META_HPP_CLANG
|
||||
#elif defined(__GNUC__)
|
||||
# define META_HPP_GCC
|
||||
#endif
|
||||
|
||||
#if defined(META_HPP_MSVC)
|
||||
# define META_HPP_MSVC_IGNORE_WARNING(w) __pragma(warning(disable : w))
|
||||
# define META_HPP_MSVC_IGNORE_WARNINGS_PUSH() __pragma(warning(push))
|
||||
# define META_HPP_MSVC_IGNORE_WARNINGS_POP() __pragma(warning(pop))
|
||||
#else
|
||||
# define META_HPP_MSVC_IGNORE_WARNING(w)
|
||||
# define META_HPP_MSVC_IGNORE_WARNINGS_PUSH()
|
||||
# define META_HPP_MSVC_IGNORE_WARNINGS_POP()
|
||||
#endif
|
||||
|
||||
#if defined(META_HPP_CLANG)
|
||||
# define META_HPP_CLANG_PRAGMA_TO_STR(x) _Pragma(#x)
|
||||
# define META_HPP_CLANG_IGNORE_WARNING(w) META_HPP_CLANG_PRAGMA_TO_STR(clang diagnostic ignored w)
|
||||
# define META_HPP_CLANG_IGNORE_WARNINGS_PUSH() _Pragma("clang diagnostic push")
|
||||
# define META_HPP_CLANG_IGNORE_WARNINGS_POP() _Pragma("clang diagnostic pop")
|
||||
#else
|
||||
# define META_HPP_CLANG_PRAGMA_TO_STR(x)
|
||||
# define META_HPP_CLANG_IGNORE_WARNING(w)
|
||||
# define META_HPP_CLANG_IGNORE_WARNINGS_PUSH()
|
||||
# define META_HPP_CLANG_IGNORE_WARNINGS_POP()
|
||||
#endif
|
||||
|
||||
#if defined(META_HPP_GCC)
|
||||
# define META_HPP_GCC_PRAGMA_TO_STR(x) _Pragma(#x)
|
||||
# define META_HPP_GCC_IGNORE_WARNING(w) META_HPP_GCC_PRAGMA_TO_STR(GCC diagnostic ignored w)
|
||||
# define META_HPP_GCC_IGNORE_WARNINGS_PUSH() _Pragma("GCC diagnostic push")
|
||||
# define META_HPP_GCC_IGNORE_WARNINGS_POP() _Pragma("GCC diagnostic pop")
|
||||
#else
|
||||
# define META_HPP_GCC_PRAGMA_TO_STR(x)
|
||||
# define META_HPP_GCC_IGNORE_WARNING(w)
|
||||
# define META_HPP_GCC_IGNORE_WARNINGS_PUSH()
|
||||
# define META_HPP_GCC_IGNORE_WARNINGS_POP()
|
||||
#endif
|
||||
|
||||
#define META_HPP_IGNORE_OVERRIDE_WARNINGS_PUSH() \
|
||||
META_HPP_MSVC_IGNORE_WARNINGS_PUSH() \
|
||||
META_HPP_CLANG_IGNORE_WARNINGS_PUSH() \
|
||||
META_HPP_GCC_IGNORE_WARNINGS_PUSH() \
|
||||
META_HPP_CLANG_IGNORE_WARNING("-Winconsistent-missing-override") \
|
||||
META_HPP_CLANG_IGNORE_WARNING("-Wsuggest-override")
|
||||
|
||||
#define META_HPP_IGNORE_OVERRIDE_WARNINGS_POP() \
|
||||
META_HPP_GCC_IGNORE_WARNINGS_POP() \
|
||||
META_HPP_CLANG_IGNORE_WARNINGS_POP() \
|
||||
META_HPP_MSVC_IGNORE_WARNINGS_POP()
|
||||
|
||||
@@ -23,6 +23,8 @@ namespace meta_hpp::detail
|
||||
enum class error_code {
|
||||
no_error,
|
||||
|
||||
bad_cast,
|
||||
|
||||
bad_const_access,
|
||||
bad_uvalue_access,
|
||||
|
||||
@@ -38,6 +40,8 @@ namespace meta_hpp::detail
|
||||
switch ( error ) {
|
||||
case error_code::no_error:
|
||||
return "no error";
|
||||
case error_code::bad_cast:
|
||||
return "bad cast";
|
||||
case error_code::bad_const_access:
|
||||
return "bad const access";
|
||||
case error_code::bad_uvalue_access:
|
||||
|
||||
45
headers/meta.hpp/meta_ucast.hpp
Normal file
45
headers/meta.hpp/meta_ucast.hpp
Normal file
@@ -0,0 +1,45 @@
|
||||
/*******************************************************************************
|
||||
* This file is part of the "https://github.com/blackmatov/meta.hpp"
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.md
|
||||
* Copyright (C) 2021-2023, by Matvey Cherevko (blackmatov@gmail.com)
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "meta_base.hpp"
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
template <
|
||||
typename To,
|
||||
typename From,
|
||||
typename ToDT = std::remove_pointer_t<To>,
|
||||
typename FromDT = std::remove_pointer_t<From> >
|
||||
concept pointer_ucast_kind //
|
||||
= (std::is_pointer_v<From> && std::is_class_v<FromDT>) //
|
||||
&& (std::is_pointer_v<To> && (std::is_class_v<ToDT> || std::is_void_v<ToDT>)) //
|
||||
&& (!std::is_const_v<FromDT> || std::is_const_v<ToDT>) //
|
||||
&& (!std::is_volatile_v<FromDT> || std::is_volatile_v<ToDT>); //
|
||||
|
||||
template <
|
||||
typename To,
|
||||
typename From,
|
||||
typename ToDT = std::remove_reference_t<To>,
|
||||
typename FromDT = std::remove_reference_t<From> >
|
||||
concept reference_ucast_kind //
|
||||
= (std::is_reference_v<From> && std::is_class_v<FromDT>) //
|
||||
&& (std::is_reference_v<To> && std::is_class_v<ToDT>) //
|
||||
&& (!std::is_const_v<FromDT> || std::is_const_v<ToDT>) //
|
||||
&& (!std::is_volatile_v<FromDT> || std::is_volatile_v<ToDT>); //
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
{
|
||||
template < typename To, typename From >
|
||||
requires detail::pointer_ucast_kind<To, From>
|
||||
To ucast(From from);
|
||||
|
||||
template < typename To, typename From >
|
||||
requires detail::reference_ucast_kind<To, From>
|
||||
To ucast(From&& from);
|
||||
}
|
||||
93
headers/meta.hpp/meta_ucast/ucast.hpp
Normal file
93
headers/meta.hpp/meta_ucast/ucast.hpp
Normal file
@@ -0,0 +1,93 @@
|
||||
/*******************************************************************************
|
||||
* This file is part of the "https://github.com/blackmatov/meta.hpp"
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.md
|
||||
* Copyright (C) 2021-2023, by Matvey Cherevko (blackmatov@gmail.com)
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../meta_base.hpp"
|
||||
#include "../meta_ucast.hpp"
|
||||
|
||||
#include "../meta_detail/type_registry.hpp"
|
||||
#include "../meta_detail/value_utilities/utraits.hpp"
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
struct polymorphic_meta_info {
|
||||
const void* ptr{};
|
||||
class_type type{};
|
||||
};
|
||||
|
||||
template < typename T >
|
||||
concept check_polymorphic_cast_support //
|
||||
= requires(type_registry& r, const T& v) {
|
||||
{ v.get_most_derived_polymorphic_meta_info(r) } -> std::convertible_to<polymorphic_meta_info>;
|
||||
};
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
{
|
||||
template < typename To, typename From >
|
||||
requires detail::pointer_ucast_kind<To, From>
|
||||
To ucast(From from) {
|
||||
using from_data_type = std::remove_pointer_t<From>;
|
||||
using to_data_type = std::remove_pointer_t<To>;
|
||||
|
||||
static_assert(
|
||||
detail::check_polymorphic_cast_support<from_data_type>,
|
||||
"The type doesn't support ucasts. Use the META_HPP_ENABLE_POLYMORPHIC_CAST macro to fix it."
|
||||
);
|
||||
|
||||
if ( from == nullptr ) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if constexpr ( std::is_same_v<std::remove_cv_t<from_data_type>, std::remove_cv_t<to_data_type>> ) {
|
||||
return from;
|
||||
}
|
||||
|
||||
detail::type_registry& registry{detail::type_registry::instance()};
|
||||
const detail::polymorphic_meta_info& meta_info{from->get_most_derived_polymorphic_meta_info(registry)};
|
||||
|
||||
// NOLINTNEXTLINE(*-const-cast)
|
||||
void* most_derived_object_ptr = const_cast<void*>(meta_info.ptr);
|
||||
|
||||
if constexpr ( std::is_void_v<std::remove_cv_t<to_data_type>> ) {
|
||||
return most_derived_object_ptr;
|
||||
} else {
|
||||
const class_type& to_class_type = registry.resolve_class_type<to_data_type>();
|
||||
return static_cast<To>(detail::pointer_upcast(most_derived_object_ptr, meta_info.type, to_class_type));
|
||||
}
|
||||
}
|
||||
|
||||
template < typename To, typename From >
|
||||
requires detail::reference_ucast_kind<To, From>
|
||||
To ucast(From&& from) {
|
||||
using from_data_type = std::remove_reference_t<From>;
|
||||
using to_data_type = std::remove_reference_t<To>;
|
||||
|
||||
static_assert(
|
||||
detail::check_polymorphic_cast_support<from_data_type>,
|
||||
"The type doesn't support ucasts. Use the META_HPP_ENABLE_POLYMORPHIC_CAST macro to fix it."
|
||||
);
|
||||
|
||||
if ( to_data_type* ptr = ucast<to_data_type*>(std::addressof(from)) ) {
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
throw_exception(error_code::bad_cast);
|
||||
}
|
||||
}
|
||||
|
||||
#define META_HPP_ENABLE_POLYMORPHIC_CAST() \
|
||||
public: \
|
||||
META_HPP_IGNORE_OVERRIDE_WARNINGS_PUSH() \
|
||||
virtual ::meta_hpp::detail::polymorphic_meta_info get_most_derived_polymorphic_meta_info( \
|
||||
::meta_hpp::detail::type_registry& registry \
|
||||
) const { \
|
||||
using self_type = std::remove_cvref_t<decltype(*this)>; \
|
||||
return ::meta_hpp::detail::polymorphic_meta_info{.ptr = this, .type = registry.resolve_class_type<self_type>()}; \
|
||||
} \
|
||||
META_HPP_IGNORE_OVERRIDE_WARNINGS_POP() \
|
||||
private:
|
||||
Reference in New Issue
Block a user