Przeglądaj źródła

poly: refined inheritance support - close #1184

Michele Caini 1 rok temu
rodzic
commit
1098b61060
3 zmienionych plików z 87 dodań i 31 usunięć
  1. 3 4
      docs/md/poly.md
  2. 11 10
      src/entt/poly/poly.hpp
  3. 73 17
      test/entt/poly/poly.cpp

+ 3 - 4
docs/md/poly.md

@@ -230,8 +230,8 @@ For a deduced concept, inheritance is achieved in a few steps:
 ```cpp
 ```cpp
 struct DrawableAndErasable: entt::type_list<> {
 struct DrawableAndErasable: entt::type_list<> {
     template<typename Base>
     template<typename Base>
-    struct type: typename Drawable::template type<Base> {
-        static constexpr auto base = std::tuple_size_v<typename entt::poly_vtable<Drawable>::type>;
+    struct type: typename Drawable::type<Base> {
+        static constexpr auto base = Drawable::impl<Drawable::type<entt::poly_inspector>>::size;
         void erase() { entt::poly_call<base + 0>(*this); }
         void erase() { entt::poly_call<base + 0>(*this); }
     };
     };
 
 
@@ -267,8 +267,7 @@ a `decltype` as it follows:
 ```cpp
 ```cpp
 struct DrawableAndErasable: entt::type_list_cat_t<
 struct DrawableAndErasable: entt::type_list_cat_t<
     decltype(as_type_list(std::declval<Drawable>())),
     decltype(as_type_list(std::declval<Drawable>())),
-    entt::type_list<void()>
-> {
+    entt::type_list<void()>> {
     // ...
     // ...
 };
 };
 ```
 ```

+ 11 - 10
src/entt/poly/poly.hpp

@@ -47,20 +47,21 @@ template<typename Concept, std::size_t Len, std::size_t Align>
 class poly_vtable {
 class poly_vtable {
     using inspector = typename Concept::template type<poly_inspector>;
     using inspector = typename Concept::template type<poly_inspector>;
 
 
-    template<typename Ret, typename... Args>
-    static auto vtable_entry(Ret (*)(inspector &, Args...)) -> Ret (*)(basic_any<Len, Align> &, Args...);
+    template<typename Ret, typename Clazz, typename... Args>
+    static auto vtable_entry(Ret (*)(Clazz &, Args...))
+        -> std::enable_if_t<std::is_base_of_v<std::remove_const_t<Clazz>, inspector>, Ret (*)(constness_as_t<basic_any<Len, Align>, Clazz> &, Args...)>;
 
 
     template<typename Ret, typename... Args>
     template<typename Ret, typename... Args>
-    static auto vtable_entry(Ret (*)(const inspector &, Args...)) -> Ret (*)(const basic_any<Len, Align> &, Args...);
+    static auto vtable_entry(Ret (*)(Args...))
+        -> Ret (*)(const basic_any<Len, Align> &, Args...);
 
 
-    template<typename Ret, typename... Args>
-    static auto vtable_entry(Ret (*)(Args...)) -> Ret (*)(const basic_any<Len, Align> &, Args...);
+    template<typename Ret, typename Clazz, typename... Args>
+    static auto vtable_entry(Ret (Clazz::*)(Args...))
+        -> std::enable_if_t<std::is_base_of_v<Clazz, inspector>, Ret (*)(basic_any<Len, Align> &, Args...)>;
 
 
-    template<typename Ret, typename... Args>
-    static auto vtable_entry(Ret (inspector::*)(Args...)) -> Ret (*)(basic_any<Len, Align> &, Args...);
-
-    template<typename Ret, typename... Args>
-    static auto vtable_entry(Ret (inspector::*)(Args...) const) -> Ret (*)(const basic_any<Len, Align> &, Args...);
+    template<typename Ret, typename Clazz, typename... Args>
+    static auto vtable_entry(Ret (Clazz::*)(Args...) const)
+        -> std::enable_if_t<std::is_base_of_v<Clazz, inspector>, Ret (*)(const basic_any<Len, Align> &, Args...)>;
 
 
     template<auto... Candidate>
     template<auto... Candidate>
     static auto make_vtable(value_list<Candidate...>) noexcept
     static auto make_vtable(value_list<Candidate...>) noexcept

+ 73 - 17
test/entt/poly/poly.cpp

@@ -55,10 +55,17 @@ struct common_members {
 
 
 namespace {
 namespace {
 
 
+template<typename... Type>
+entt::type_list<Type...> as_type_list(const entt::type_list<Type...> &);
+
 [[nodiscard]] int absolutely_random() {
 [[nodiscard]] int absolutely_random() {
     return 4;
     return 4;
 }
 }
 
 
+[[nodiscard]] int three_is_a_magic_number() {
+    return 3;
+}
+
 } // namespace
 } // namespace
 
 
 template<typename Type>
 template<typename Type>
@@ -127,6 +134,38 @@ struct DefinedEmbedded
     using impl = entt::value_list<&Type::get>;
     using impl = entt::value_list<&Type::get>;
 };
 };
 
 
+struct DeducedDerived
+    : entt::type_list<> {
+    template<typename Base>
+    struct type: Deduced::type<Base> {
+        static constexpr auto base = Deduced::impl<Deduced::type<entt::poly_inspector>>::size;
+
+        int three_is_a_magic_number() {
+            return entt::poly_call<base + 0>(*this);
+        }
+    };
+
+    template<typename Type>
+    using impl = entt::value_list_cat_t<typename Deduced::impl<Type>, entt::value_list<&three_is_a_magic_number>>;
+};
+
+struct DefinedDerived
+    : entt::type_list_cat_t<
+          decltype(as_type_list(std::declval<Defined>())),
+          entt::type_list<int()>> {
+    template<typename Base>
+    struct type: Defined::type<Base> {
+        static constexpr auto base = Defined::impl<Defined::type<entt::poly_inspector>>::size;
+
+        int three_is_a_magic_number() {
+            return entt::poly_call<base + 0>(*this);
+        }
+    };
+
+    template<typename Type>
+    using impl = entt::value_list_cat_t<typename Defined::impl<Type>, entt::value_list<&three_is_a_magic_number>>;
+};
+
 struct impl {
 struct impl {
     impl() = default;
     impl() = default;
 
 
@@ -173,6 +212,15 @@ using PolyEmbeddedTypes = ::testing::Types<DeducedEmbedded, DefinedEmbedded>;
 
 
 TYPED_TEST_SUITE(PolyEmbedded, PolyEmbeddedTypes, );
 TYPED_TEST_SUITE(PolyEmbedded, PolyEmbeddedTypes, );
 
 
+template<typename Type>
+struct PolyDerived: testing::Test {
+    using type = entt::basic_poly<Type>;
+};
+
+using PolyDerivedTypes = ::testing::Types<DeducedDerived, DefinedDerived>;
+
+TYPED_TEST_SUITE(PolyDerived, PolyDerivedTypes, );
+
 TYPED_TEST(Poly, Functionalities) {
 TYPED_TEST(Poly, Functionalities) {
     using poly_type = typename TestFixture::template type<>;
     using poly_type = typename TestFixture::template type<>;
 
 
@@ -196,7 +244,7 @@ TYPED_TEST(Poly, Functionalities) {
     ASSERT_EQ(alias.data(), &instance);
     ASSERT_EQ(alias.data(), &instance);
     ASSERT_EQ(std::as_const(alias).data(), &instance);
     ASSERT_EQ(std::as_const(alias).data(), &instance);
 
 
-    ASSERT_EQ(value->rand(), 4);
+    ASSERT_EQ(value->rand(), absolutely_random());
 
 
     empty = impl{};
     empty = impl{};
 
 
@@ -243,22 +291,6 @@ TYPED_TEST(Poly, Functionalities) {
     ASSERT_EQ(move.type(), entt::type_id<void>());
     ASSERT_EQ(move.type(), entt::type_id<void>());
 }
 }
 
 
-TYPED_TEST(PolyEmbedded, EmbeddedVtable) {
-    using poly_type = typename TestFixture::type;
-
-    poly_type poly{impl{}};
-    auto *ptr = static_cast<impl *>(poly.data());
-
-    ASSERT_TRUE(poly);
-    ASSERT_NE(poly.data(), nullptr);
-    ASSERT_NE(std::as_const(poly).data(), nullptr);
-    ASSERT_EQ(poly->get(), 0);
-
-    ptr->value = 2;
-
-    ASSERT_EQ(poly->get(), 2);
-}
-
 TYPED_TEST(Poly, Owned) {
 TYPED_TEST(Poly, Owned) {
     using poly_type = typename TestFixture::template type<>;
     using poly_type = typename TestFixture::template type<>;
 
 
@@ -440,3 +472,27 @@ TYPED_TEST(Poly, NoSboAlignment) {
 
 
     ASSERT_EQ(data, nosbo[1].data());
     ASSERT_EQ(data, nosbo[1].data());
 }
 }
+
+TYPED_TEST(PolyEmbedded, EmbeddedVtable) {
+    using poly_type = typename TestFixture::type;
+
+    poly_type poly{impl{}};
+    auto *ptr = static_cast<impl *>(poly.data());
+
+    ASSERT_TRUE(poly);
+    ASSERT_NE(poly.data(), nullptr);
+    ASSERT_NE(std::as_const(poly).data(), nullptr);
+    ASSERT_EQ(poly->get(), 0);
+
+    ptr->value = 2;
+
+    ASSERT_EQ(poly->get(), 2);
+}
+
+TYPED_TEST(PolyDerived, InheritanceSupport) {
+    using poly_type = typename TestFixture::type;
+
+    poly_type poly{impl{}};
+
+    ASSERT_EQ(poly->three_is_a_magic_number(), three_is_a_magic_number());
+}