Browse Source

meta: meta_type::invoke also searches into the base types for a candidate function

Michele Caini 4 years ago
parent
commit
3443987127
2 changed files with 25 additions and 12 deletions
  1. 12 11
      src/entt/meta/meta.hpp
  2. 13 1
      test/entt/meta/meta_type.cpp

+ 12 - 11
src/entt/meta/meta.hpp

@@ -786,8 +786,7 @@ struct meta_data {
      * @brief Sets the value of a given variable.
      *
      * It must be possible to cast the instance to the parent type of the data
-     * member. Otherwise, invoking the setter results in an undefined
-     * behavior.<br/>
+     * member.<br/>
      * The type of the value is such that a cast or conversion to the type of
      * the variable is possible. Otherwise, invoking the setter does nothing.
      *
@@ -805,7 +804,7 @@ struct meta_data {
      * @brief Gets the value of a given variable.
      *
      * It must be possible to cast the instance to the parent type of the data
-     * member. Otherwise, invoking the getter results in an undefined behavior.
+     * member.
      *
      * @param instance An opaque instance of the underlying type.
      * @return A wrapper containing the value of the underlying variable.
@@ -916,8 +915,7 @@ struct meta_func {
      * conversion to the required types is possible. Otherwise, an empty and
      * thus invalid wrapper is returned.<br/>
      * It must be possible to cast the instance to the parent type of the member
-     * function. Otherwise, invoking the underlying function results in an
-     * undefined behavior.
+     * function.
      *
      * @param instance An opaque instance of the underlying type.
      * @param args Parameters to use to invoke the function.
@@ -979,7 +977,7 @@ private:
 /*! @brief Opaque wrapper for types. */
 class meta_type {
     template<auto Member, typename Pred>
-    [[nodiscard]] const auto *lookup(meta_any *const args, const typename internal::meta_type_node::size_type sz, Pred pred) const {
+    [[nodiscard]] std::decay_t<decltype(std::declval<internal::meta_type_node>().*Member)> lookup(meta_any *const args, const typename internal::meta_type_node::size_type sz, Pred pred) const {
         std::decay_t<decltype(node->*Member)> candidate{};
         size_type extent{sz + 1u};
         bool ambiguous{};
@@ -1258,8 +1256,7 @@ public:
      * @brief Invokes a function given an identifier, if possible.
      *
      * It must be possible to cast the instance to the parent type of the member
-     * function. Otherwise, invoking the underlying function results in an
-     * undefined behavior.
+     * function.
      *
      * @sa meta_func::invoke
      *
@@ -1271,6 +1268,11 @@ public:
      */
     meta_any invoke(const id_type id, meta_handle instance, meta_any *const args, const size_type sz) const {
         const auto *candidate = lookup<&node_type::func>(args, sz, [id](const auto *curr) { return curr->id == id; });
+
+        for(auto it = base().begin(), last = base().end(); it != last && !candidate; ++it) {
+            candidate = it->lookup<&node_type::func>(args, sz, [id](const auto *curr) { return curr->id == id; });
+        }
+
         return candidate ? candidate->invoke(std::move(instance), args) : meta_any{};
     }
 
@@ -1295,8 +1297,7 @@ public:
      * @brief Sets the value of a given variable.
      *
      * It must be possible to cast the instance to the parent type of the data
-     * member. Otherwise, invoking the setter results in an undefined
-     * behavior.<br/>
+     * member.<br/>
      * The type of the value is such that a cast or conversion to the type of
      * the variable is possible. Otherwise, invoking the setter does nothing.
      *
@@ -1316,7 +1317,7 @@ public:
      * @brief Gets the value of a given variable.
      *
      * It must be possible to cast the instance to the parent type of the data
-     * member. Otherwise, invoking the getter results in an undefined behavior.
+     * member.
      *
      * @param id Unique identifier.
      * @param instance An opaque instance of the underlying type.

+ 13 - 1
test/entt/meta/meta_type.cpp

@@ -37,6 +37,7 @@ struct abstract_t {
     virtual ~abstract_t() = default;
 
     virtual void func(int) {}
+    void base_only(int) {}
 };
 
 struct concrete_t: base_t, abstract_t {
@@ -124,7 +125,8 @@ struct MetaType: ::testing::Test {
 
         entt::meta<abstract_t>()
             .type("abstract"_hs)
-            .func<&abstract_t::func>("func"_hs);
+            .func<&abstract_t::func>("func"_hs)
+            .func<&abstract_t::base_only>("base_only"_hs);
 
         entt::meta<concrete_t>()
             .type("concrete"_hs)
@@ -339,6 +341,16 @@ TEST_F(MetaType, Invoke) {
     ASSERT_FALSE(type.invoke("rebmem"_hs, {}));
 }
 
+TEST_F(MetaType, InvokeFromBase) {
+    using namespace entt::literals;
+
+    auto type = entt::resolve<concrete_t>();
+    concrete_t instance{};
+
+    ASSERT_TRUE(type.invoke("base_only"_hs, instance, 42));
+    ASSERT_FALSE(type.invoke("ylno_esab"_hs, {}, 'c'));
+}
+
 TEST_F(MetaType, OverloadedFunc) {
     using namespace entt::literals;