Sfoglia il codice sorgente

registry: reintroduce old function type for signals, the registry is now provided to listeners

Michele Caini 5 anni fa
parent
commit
826d7b7c26

+ 7 - 9
docs/md/entity.md

@@ -375,7 +375,7 @@ attached to `on_update` will only be invoked following a call to `replace` or
 The function type of a listener should be equivalent to the following:
 
 ```cpp
-void(entt::entity);
+void(entt::registry &, entt::entity);
 ```
 
 Note also that:
@@ -630,25 +630,25 @@ that isn't associated with the given registry can result in undefined behavior.
 
 The `registry` class is designed to be able to create short circuits between its
 functions. This simplifies the definition of _dependencies_ between different
-operations and registries.<br/>
+operations.<br/>
 For example, the following adds (or replaces) the component `a_type` whenever
 `my_type` is assigned to an entity:
 
 ```cpp
-registry.on_construct<my_type>().connect<&entt::registry::emplace_or_replace<a_type>>(registry);
+registry.on_construct<my_type>().connect<&entt::registry::emplace_or_replace<a_type>>();
 ```
 
 Similarly, the code shown below removes `a_type` from an entity whenever
 `my_type` is assigned to it:
 
 ```cpp
-registry.on_construct<my_type>().connect<&entt::registry::remove<a_type>>(registry);
+registry.on_construct<my_type>().connect<&entt::registry::remove<a_type>>();
 ```
 
 A dependency can also be easily broken as follows:
 
 ```cpp
-registry.on_construct<my_type>().disconnect<&entt::registry::emplace_or_replace<a_type>>(registry);
+registry.on_construct<my_type>().disconnect<&entt::registry::emplace_or_replace<a_type>>();
 ```
 
 There are many other types of dependencies. In general, most of the functions
@@ -663,13 +663,11 @@ _extend_ their classes and this may not always be possible.<br/>
 The `invoke` helper allows to _propagate_ the signal in these cases:
 
 ```cpp
-registry.on_construct<clazz>().connect<entt::invoke<&clazz::func>>(registry);
+registry.on_construct<clazz>().connect<entt::invoke<&clazz::func>>();
 ```
 
 All it does is pick up the _right_ component for the received entity and invoke
-the requested method, passing on the arguments if necessary.<br/>
-The registry is also supplied by the invoker directly to the function invoked as
-the first argument.
+the requested method, passing on the arguments if necessary.
 
 ### Handle
 

+ 17 - 19
src/entt/entity/observer.hpp

@@ -9,6 +9,7 @@
 #include <type_traits>
 #include "../config/config.h"
 #include "../core/type_traits.hpp"
+#include "../signal/delegate.hpp"
 #include "registry.hpp"
 #include "storage.hpp"
 #include "utility.hpp"
@@ -177,8 +178,8 @@ class basic_observer {
     template<typename... Reject, typename... Require, typename AnyOf>
     struct matcher_handler<matcher<type_list<Reject...>, type_list<Require...>, AnyOf>> {
         template<std::size_t Index>
-        static void maybe_valid_if(basic_observer &obs, const Entity entt) {
-            if(obs.target->template has<Require...>(entt) && !obs.target->template any<Reject...>(entt)) {
+        static void maybe_valid_if(basic_observer &obs, basic_registry<Entity> &reg, const Entity entt) {
+            if(reg.template has<Require...>(entt) && !reg.template any<Reject...>(entt)) {
                 if(auto *comp = obs.view.try_get(entt); !comp) {
                     obs.view.emplace(entt);
                 }
@@ -188,7 +189,7 @@ class basic_observer {
         }
 
         template<std::size_t Index>
-        static void discard_if(basic_observer &obs, const Entity entt) {
+        static void discard_if(basic_observer &obs, basic_registry<Entity> &, const Entity entt) {
             if(auto *value = obs.view.try_get(entt); value && !(*value &= (~(1 << Index)))) {
                 obs.view.erase(entt);
             }
@@ -213,12 +214,12 @@ class basic_observer {
     template<typename... Reject, typename... Require, typename... NoneOf, typename... AllOf>
     struct matcher_handler<matcher<type_list<Reject...>, type_list<Require...>, type_list<NoneOf...>, AllOf...>> {
         template<std::size_t Index, typename... Ignore>
-        static void maybe_valid_if(basic_observer &obs, const Entity entt) {
-            if([&obs, entt]() {
+        static void maybe_valid_if(basic_observer &obs, basic_registry<Entity> &reg, const Entity entt) {
+            if([&reg, entt]() {
                 if constexpr(sizeof...(Ignore) == 0) {
-                    return obs.target->template has<AllOf..., Require...>(entt) && !obs.target->template any<NoneOf..., Reject...>(entt);
+                    return reg.template has<AllOf..., Require...>(entt) && !reg.template any<NoneOf..., Reject...>(entt);
                 } else {
-                    return obs.target->template has<AllOf..., Require...>(entt) && ((std::is_same_v<Ignore..., NoneOf> || !obs.target->template any<NoneOf>(entt)) && ...) && !obs.target->template any<Reject...>(entt);
+                    return reg.template has<AllOf..., Require...>(entt) && ((std::is_same_v<Ignore..., NoneOf> || !reg.template any<NoneOf>(entt)) && ...) && !reg.template any<Reject...>(entt);
                 }
             }())
             {
@@ -231,7 +232,7 @@ class basic_observer {
         }
 
         template<std::size_t Index>
-        static void discard_if(basic_observer &obs, const Entity entt) {
+        static void discard_if(basic_observer &obs, basic_registry<Entity> &, const Entity entt) {
             if(auto *value = obs.view.try_get(entt); value && !(*value &= (~(1 << Index)))) {
                 obs.view.erase(entt);
             }
@@ -258,7 +259,7 @@ class basic_observer {
     };
 
     template<typename... Matcher>
-    static void disconnect(basic_observer &obs, basic_registry<Entity> &reg) {
+    static void disconnect(basic_registry<Entity> &reg, basic_observer &obs) {
         (matcher_handler<Matcher>::disconnect(obs, reg), ...);
     }
 
@@ -266,7 +267,7 @@ class basic_observer {
     void connect(basic_registry<Entity> &reg, std::index_sequence<Index...>) {
         static_assert(sizeof...(Matcher) < std::numeric_limits<payload_type>::digits, "Too many matchers");
         (matcher_handler<Matcher>::template connect<Index>(*this, reg), ...);
-        release = &basic_observer::disconnect<Matcher...>;
+        release.template connect<&basic_observer::disconnect<Matcher...>>(reg);
     }
 
 public:
@@ -279,7 +280,8 @@ public:
 
     /*! @brief Default constructor. */
     basic_observer()
-        : target{}, release{}, view{}
+        : release{},
+          view{}
     {}
 
     /*! @brief Default copy constructor, deleted on purpose. */
@@ -294,9 +296,7 @@ public:
      */
     template<typename... Matcher>
     basic_observer(basic_registry<entity_type> &reg, basic_collector<Matcher...>)
-        : target{&reg},
-          release{},
-          view{}
+        : basic_observer{}
     {
         connect<Matcher...>(reg, std::index_sequence_for<Matcher...>{});
     }
@@ -325,15 +325,14 @@ public:
     void connect(basic_registry<entity_type> &reg, basic_collector<Matcher...>) {
         disconnect();
         connect<Matcher...>(reg, std::index_sequence_for<Matcher...>{});
-        target = &reg;
         view.clear();
     }
 
     /*! @brief Disconnects an observer from the registry it keeps track of. */
     void disconnect() {
         if(release) {
-            release(*this, *target);
-            release = nullptr;
+            release(*this);
+            release.reset();
         }
     }
 
@@ -436,8 +435,7 @@ public:
     }
 
 private:
-    basic_registry<entity_type> *target;
-    void(* release)(basic_observer &, basic_registry<entity_type> &);
+    delegate<void(basic_observer &)> release;
     storage<entity_type, payload_type> view;
 };
 

+ 27 - 20
src/entt/entity/pool.hpp

@@ -8,6 +8,7 @@
 #include "../config/config.h"
 #include "../core/type_traits.hpp"
 #include "../signal/sigh.hpp"
+#include "fwd.hpp"
 #include "storage.hpp"
 
 
@@ -36,7 +37,7 @@ struct default_pool final: storage<Entity, Type> {
     * The function type for a listener is equivalent to:
     *
     * @code{.cpp}
-    * void(Entity);
+    * void(basic_registry<Entity> &, Entity);
     * @endcode
     *
     * Listeners are invoked **after** the object has been assigned to the
@@ -58,7 +59,7 @@ struct default_pool final: storage<Entity, Type> {
     * The function type for a listener is equivalent to:
     *
     * @code{.cpp}
-    * void(Entity);
+    * void(basic_registry<Entity> &, Entity);
     * @endcode
     *
     * Listeners are invoked **after** the object has been updated.
@@ -79,7 +80,7 @@ struct default_pool final: storage<Entity, Type> {
     * The function type for a listener is equivalent to:
     *
     * @code{.cpp}
-    * void(Entity);
+    * void(basic_registry<Entity> &, Entity);
     * @endcode
     *
     * Listeners are invoked **before** the object has been removed from the
@@ -107,14 +108,15 @@ struct default_pool final: storage<Entity, Type> {
     * invalid entity or if the entity already belongs to the pool.
     *
     * @tparam Args Types of arguments to use to construct the object.
+    * @param owner The registry that issued the request.
     * @param entity A valid entity identifier.
     * @param args Parameters to use to initialize the object.
     * @return A reference to the newly created object.
     */
     template<typename... Args>
-    decltype(auto) emplace(const entity_type entity, Args &&... args) {
+    decltype(auto) emplace(basic_registry<entity_type> &owner, const entity_type entity, Args &&... args) {
         storage<entity_type, Type>::emplace(entity, std::forward<Args>(args)...);
-        construction.publish(entity);
+        construction.publish(owner, entity);
 
         if constexpr(!is_eto_eligible_v<object_type>) {
             return this->get(entity);
@@ -128,17 +130,18 @@ struct default_pool final: storage<Entity, Type> {
     *
     * @tparam It Type of input iterator.
     * @tparam Args Types of arguments to use to construct the object.
+    * @param owner The registry that issued the request.
     * @param first An iterator to the first element of the range of entities.
     * @param last An iterator past the last element of the range of entities.
     * @param args Parameters to use to initialize the object.
     */
     template<typename It, typename... Args>
-    void insert(It first, It last, Args &&... args) {
+    void insert(basic_registry<entity_type> &owner, It first, It last, Args &&... args) {
         storage<entity_type, object_type>::insert(first, last, std::forward<Args>(args)...);
 
         if(!construction.empty()) {
             for(; first != last; ++first) {
-                construction.publish(*first);
+                construction.publish(owner, *first);
             }
         }
     }
@@ -152,10 +155,11 @@ struct default_pool final: storage<Entity, Type> {
     * An assertion will abort the execution at runtime in debug mode in case of
     * invalid entity or if the entity doesn't belong to the pool.
     *
+    * @param owner The registry that issued the request.
     * @param entity A valid entity identifier.
     */
-    void erase(const entity_type entity) override {
-        destruction.publish(entity);
+    void erase(basic_registry<entity_type> &owner, const entity_type entity) {
+        destruction.publish(owner, entity);
         storage<entity_type, object_type>::erase(entity);
     }
 
@@ -165,22 +169,23 @@ struct default_pool final: storage<Entity, Type> {
     * @see remove
     *
     * @tparam It Type of input iterator.
+    * @param owner The registry that issued the request.
     * @param first An iterator to the first element of the range of entities.
     * @param last An iterator past the last element of the range of entities.
     */
     template<typename It>
-    void erase(It first, It last) {
+    void erase(basic_registry<entity_type> &owner, It first, It last) {
         if(std::distance(first, last) == std::distance(this->begin(), this->end())) {
             if(!destruction.empty()) {
                 for(; first != last; ++first) {
-                    destruction.publish(*first);
+                    destruction.publish(owner, *first);
                 }
             }
 
             this->clear();
         } else {
             for(; first != last; ++first) {
-                this->erase(*first);
+                this->erase(owner, *first);
             }
         }
     }
@@ -206,17 +211,18 @@ struct default_pool final: storage<Entity, Type> {
     * invalid entity or if the entity doesn't belong to the pool.
     *
     * @tparam Func Types of the function objects to invoke.
+    * @param owner The registry that issued the request.
     * @param entity A valid entity identifier.
     * @param func Valid function objects.
     * @return A reference to the patched instance.
     */
     template<typename... Func>
-    decltype(auto) patch(const entity_type entity, [[maybe_unused]] Func &&... func) {
+    decltype(auto) patch(basic_registry<entity_type> &owner, const entity_type entity, [[maybe_unused]] Func &&... func) {
         if constexpr(is_eto_eligible_v<object_type>) {
-            update.publish(entity);
+            update.publish(owner, entity);
         } else {
             (std::forward<Func>(func)(this->get(entity)), ...);
-            update.publish(entity);
+            update.publish(owner, entity);
             return this->get(entity);
         }
     }
@@ -234,18 +240,19 @@ struct default_pool final: storage<Entity, Type> {
     * An assertion will abort the execution at runtime in debug mode in case of
     * invalid entity or if the entity doesn't belong to the pool.
     *
+    * @param owner The registry that issued the request.
     * @param entity A valid entity identifier.
     * @param value An instance of the type to assign.
     * @return A reference to the object being replaced.
     */
-    decltype(auto) replace(const entity_type entity, object_type value) {
-        return patch(entity, [&value](auto &&curr) { curr = std::move(value); });
+    decltype(auto) replace(basic_registry<entity_type> &owner, const entity_type entity, object_type value) {
+        return patch(owner, entity, [&value](auto &&curr) { curr = std::move(value); });
     }
 
 private:
-    sigh<void(const entity_type)> construction{};
-    sigh<void(const entity_type)> destruction{};
-    sigh<void(const entity_type)> update{};
+    sigh<void(basic_registry<entity_type> &, const entity_type)> construction{};
+    sigh<void(basic_registry<entity_type> &, const entity_type)> destruction{};
+    sigh<void(basic_registry<entity_type> &, const entity_type)> update{};
 };
 
 

+ 40 - 38
src/entt/entity/registry.hpp

@@ -45,6 +45,7 @@ class basic_registry {
     struct pool_data {
         id_type type_id{};
         std::unique_ptr<sparse_set<Entity>> pool{};
+        void(* erase)(sparse_set<Entity> &, basic_registry &, const Entity);
     };
 
     template<typename...>
@@ -54,19 +55,14 @@ class basic_registry {
     struct group_handler<exclude_t<Exclude...>, get_t<Get...>, Owned...> {
         static_assert(std::conjunction_v<std::is_same<Owned, std::decay_t<Owned>>..., std::is_same<Get, std::decay_t<Get>>..., std::is_same<Exclude, std::decay_t<Exclude>>...>, "One or more component types are invalid");
         std::conditional_t<sizeof...(Owned) == 0, sparse_set<Entity>, std::size_t> current{};
-        basic_registry *owner;
-
-        group_handler(basic_registry &parent)
-            : owner{&parent}
-        {}
 
         template<typename Component>
-        void maybe_valid_if(const Entity entt) {
-            [[maybe_unused]] const auto cpools = std::forward_as_tuple(owner->assure<Owned>()...);
+        void maybe_valid_if(basic_registry &owner, const Entity entt) {
+            [[maybe_unused]] const auto cpools = std::forward_as_tuple(owner.assure<Owned>()...);
 
             const auto is_valid = ((std::is_same_v<Component, Owned> || std::get<pool_t<Entity, Owned> &>(cpools).contains(entt)) && ...)
-                    && ((std::is_same_v<Component, Get> || owner->assure<Get>().contains(entt)) && ...)
-                    && ((std::is_same_v<Component, Exclude> || !owner->assure<Exclude>().contains(entt)) && ...);
+                    && ((std::is_same_v<Component, Get> || owner.assure<Get>().contains(entt)) && ...)
+                    && ((std::is_same_v<Component, Exclude> || !owner.assure<Exclude>().contains(entt)) && ...);
 
             if constexpr(sizeof...(Owned) == 0) {
                 if(is_valid && !current.contains(entt)) {
@@ -80,13 +76,13 @@ class basic_registry {
             }
         }
 
-        void discard_if(const Entity entt) {
+        void discard_if([[maybe_unused]] basic_registry &owner, const Entity entt) {
             if constexpr(sizeof...(Owned) == 0) {
                 if(current.contains(entt)) {
                     current.erase(entt);
                 }
             } else {
-                if(const auto cpools = std::forward_as_tuple(owner->assure<Owned>()...); std::get<0>(cpools).contains(entt) && (std::get<0>(cpools).index(entt) < current)) {
+                if(const auto cpools = std::forward_as_tuple(owner.assure<Owned>()...); std::get<0>(cpools).contains(entt) && (std::get<0>(cpools).index(entt) < current)) {
                     const auto pos = --current;
                     (std::get<pool_t<Entity, Owned> &>(cpools).swap(std::get<pool_t<Entity, Owned> &>(cpools).data()[pos], entt), ...);
                 }
@@ -109,7 +105,7 @@ class basic_registry {
 
     template<typename Component>
     [[nodiscard]] const pool_t<Entity, Component> & assure() const {
-        const sparse_set<entity_type> *cpool;
+        const sparse_set<entity_type> *curr;
 
         if constexpr(ENTT_FAST_PATH(has_type_index_v<Component>)) {
             const auto index = type_index<Component>::value();
@@ -120,22 +116,28 @@ class basic_registry {
 
             if(auto &&pdata = pools[index]; !pdata.pool) {
                 pdata.type_id = type_info<Component>::id();
-                pdata.pool.reset(new pool_t<Entity, Component>());
+                pdata.pool.reset(new pool_t<Entity, Component>{});
+                pdata.erase = +[](sparse_set<Entity> &cpool, basic_registry &owner, const Entity entt) {
+                    static_cast<pool_t<Entity, Component> &>(cpool).erase(owner, entt);
+                };
             }
 
-            cpool = pools[index].pool.get();
+            curr = pools[index].pool.get();
         } else {
             if(const auto it = std::find_if(pools.cbegin(), pools.cend(), [id = type_info<Component>::id()](const auto &pdata) { return id == pdata.type_id; }); it == pools.cend()) {
-                cpool = pools.emplace_back(pool_data{
+                curr = pools.emplace_back(pool_data{
                     type_info<Component>::id(),
-                    std::unique_ptr<sparse_set<entity_type>>{new pool_t<Entity, Component>()}
+                    std::unique_ptr<sparse_set<entity_type>>{new pool_t<Entity, Component>{}},
+                    +[](sparse_set<Entity> &cpool, basic_registry &owner, const Entity entt) {
+                        static_cast<pool_t<Entity, Component> &>(cpool).erase(owner, entt);
+                    }
                 }).pool.get();
             } else {
-                cpool = it->pool.get();
+                curr = it->pool.get();
             }
         }
 
-        return *static_cast<const pool_t<Entity, Component> *>(cpool);
+        return *static_cast<const pool_t<Entity, Component> *>(curr);
     }
 
     template<typename Component>
@@ -569,7 +571,7 @@ public:
     template<typename Component, typename... Args>
     decltype(auto) emplace(const entity_type entity, Args &&... args) {
         ENTT_ASSERT(valid(entity));
-        return assure<Component>().emplace(entity, std::forward<Args>(args)...);
+        return assure<Component>().emplace(*this, entity, std::forward<Args>(args)...);
     }
 
     /**
@@ -586,7 +588,7 @@ public:
     template<typename Component, typename It>
     void insert(It first, It last, const Component &value = {}) {
         ENTT_ASSERT(std::all_of(first, last, [this](const auto entity) { return valid(entity); }));
-        assure<Component>().insert(first, last, value);
+        assure<Component>().insert(*this, first, last, value);
     }
 
     /**
@@ -606,7 +608,7 @@ public:
     void insert(EIt first, EIt last, CIt from, CIt to) {
         static_assert(std::is_constructible_v<Component, typename std::iterator_traits<CIt>::value_type>, "Invalid value type");
         ENTT_ASSERT(std::all_of(first, last, [this](const auto entity) { return valid(entity); }));
-        assure<Component>().insert(first, last, from, to);
+        assure<Component>().insert(*this, first, last, from, to);
     }
 
     /**
@@ -637,8 +639,8 @@ public:
         auto &cpool = assure<Component>();
 
         return cpool.contains(entity)
-                ? cpool.replace(entity, Component{std::forward<Args>(args)...})
-                : cpool.emplace(entity, std::forward<Args>(args)...);
+                ? cpool.replace(*this, entity, Component{std::forward<Args>(args)...})
+                : cpool.emplace(*this, entity, std::forward<Args>(args)...);
     }
 
     /**
@@ -671,7 +673,7 @@ public:
     template<typename Component, typename... Func>
     decltype(auto) patch(const entity_type entity, Func &&... func) {
         ENTT_ASSERT(valid(entity));
-        return assure<Component>().patch(entity, std::forward<Func>(func)...);
+        return assure<Component>().patch(*this, entity, std::forward<Func>(func)...);
     }
 
     /**
@@ -696,7 +698,7 @@ public:
      */
     template<typename Component, typename... Args>
     decltype(auto) replace(const entity_type entity, Args &&... args) {
-        return assure<Component>().replace(entity, Component{std::forward<Args>(args)...});
+        return assure<Component>().replace(*this, entity, Component{std::forward<Args>(args)...});
     }
 
     /**
@@ -715,7 +717,7 @@ public:
     template<typename... Component>
     void remove(const entity_type entity) {
         ENTT_ASSERT(valid(entity));
-        (assure<Component>().erase(entity), ...);
+        (assure<Component>().erase(*this, entity), ...);
     }
 
     /**
@@ -731,7 +733,7 @@ public:
     template<typename... Component, typename It>
     void remove(It first, It last) {
         ENTT_ASSERT(std::all_of(first, last, [this](const auto entity) { return valid(entity); }));
-        (assure<Component>().erase(first, last), ...);
+        (assure<Component>().erase(*this, first, last), ...);
     }
 
     /**
@@ -758,8 +760,8 @@ public:
     size_type remove_if_exists(const entity_type entity) {
         ENTT_ASSERT(valid(entity));
 
-        return ([entity](auto &&cpool) {
-            return cpool.contains(entity) ? (cpool.erase(entity), true) : false;
+        return ([this, entity](auto &&cpool) {
+            return cpool.contains(entity) ? (cpool.erase(*this, entity), true) : false;
         }(assure<Component>()) + ... + size_type{});
     }
 
@@ -784,7 +786,7 @@ public:
 
         for(auto pos = pools.size(); pos; --pos) {
             if(auto &pdata = pools[pos-1]; pdata.pool && pdata.pool->contains(entity)) {
-                pdata.pool->erase(entity);
+                pdata.erase(*pdata.pool, *this, entity);
             }
         }
     }
@@ -891,7 +893,7 @@ public:
     [[nodiscard]] decltype(auto) get_or_emplace(const entity_type entity, Args &&... args) {
         ENTT_ASSERT(valid(entity));
         auto &cpool = assure<Component>();
-        return cpool.contains(entity) ? cpool.get(entity) : cpool.emplace(entity, std::forward<Args>(args)...);
+        return cpool.contains(entity) ? cpool.get(entity) : cpool.emplace(*this, entity, std::forward<Args>(args)...);
     }
 
     /**
@@ -939,8 +941,8 @@ public:
             // useless this-> used to suppress a warning with clang
             each([this](const auto entity) { this->destroy(entity); });
         } else {
-            ([](auto &&cpool) {
-                cpool.erase(cpool.sparse_set<entity_type>::begin(), cpool.sparse_set<entity_type>::end());
+            ([this](auto &&cpool) {
+                cpool.erase(*this, cpool.sparse_set<entity_type>::begin(), cpool.sparse_set<entity_type>::end());
             }(assure<Component>()), ...);
         }
     }
@@ -1021,7 +1023,7 @@ public:
      * The function type for a listener is equivalent to:
      *
      * @code{.cpp}
-     * void(Entity);
+     * void(basic_registry<Entity> &, Entity);
      * @endcode
      *
      * Listeners are invoked **after** the component has been assigned to the
@@ -1045,7 +1047,7 @@ public:
      * The function type for a listener is equivalent to:
      *
      * @code{.cpp}
-     * void(Entity);
+     * void(basic_registry<Entity> &, Entity);
      * @endcode
      *
      * Listeners are invoked **after** the component has been updated.
@@ -1069,7 +1071,7 @@ public:
      * The function type for a listener is equivalent to:
      *
      * @code{.cpp}
-     * void(Entity);
+     * void(basic_registry<Entity> &, Entity);
      * @endcode
      *
      * Listeners are invoked **before** the component has been removed from the
@@ -1227,7 +1229,7 @@ public:
         if(!handler) {
             group_data candidate = {
                 size,
-                { new handler_type{*this}, [](void *instance) { delete static_cast<handler_type *>(instance); } },
+                { new handler_type{}, [](void *instance) { delete static_cast<handler_type *>(instance); } },
                 []([[maybe_unused]] const id_type ctype) ENTT_NOEXCEPT { return ((ctype == type_info<std::decay_t<Owned>>::id()) || ...); },
                 []([[maybe_unused]] const id_type ctype) ENTT_NOEXCEPT { return ((ctype == type_info<std::decay_t<Get>>::id()) || ...); },
                 []([[maybe_unused]] const id_type ctype) ENTT_NOEXCEPT { return ((ctype == type_info<Exclude>::id()) || ...); },
@@ -1275,7 +1277,7 @@ public:
             } else {
                 // we cannot iterate backwards because we want to leave behind valid entities in case of owned types
                 for(auto *first = std::get<0>(cpools).data(), *last = first + std::get<0>(cpools).size(); first != last; ++first) {
-                    handler->template maybe_valid_if<std::tuple_element_t<0, std::tuple<std::decay_t<Owned>...>>>(*first);
+                    handler->template maybe_valid_if<std::tuple_element_t<0, std::tuple<std::decay_t<Owned>...>>>(*this, *first);
                 }
             }
         }

+ 2 - 2
test/entt/entity/group.cpp

@@ -570,7 +570,7 @@ TEST(NonOwningGroup, FrontBack) {
 
 TEST(NonOwningGroup, SignalRace) {
     entt::registry registry;
-    registry.on_construct<double>().connect<&entt::registry::emplace_or_replace<int>>(registry);
+    registry.on_construct<double>().connect<&entt::registry::emplace_or_replace<int>>();
     const auto group = registry.group(entt::get<int, double>);
 
     auto entity = registry.create();
@@ -1227,7 +1227,7 @@ TEST(OwningGroup, FrontBack) {
 
 TEST(OwningGroup, SignalRace) {
     entt::registry registry;
-    registry.on_construct<double>().connect<&entt::registry::emplace_or_replace<int>>(registry);
+    registry.on_construct<double>().connect<&entt::registry::emplace_or_replace<int>>();
     const auto group = registry.group<int>(entt::get<double>);
 
     auto entity = registry.create();

+ 1 - 1
test/entt/entity/helper.cpp

@@ -33,7 +33,7 @@ TEST(Helper, Invoke) {
     entt::registry registry;
     const auto entity = registry.create();
 
-    registry.on_construct<clazz>().connect<entt::invoke<&clazz::func>>(registry);
+    registry.on_construct<clazz>().connect<entt::invoke<&clazz::func>>();
     registry.emplace<clazz>(entity);
 
     ASSERT_EQ(entity, registry.get<clazz>(entity).entt);

+ 7 - 7
test/entt/entity/registry.cpp

@@ -27,13 +27,13 @@ struct listener {
     }
 
     template<typename Component>
-    void incr(entt::entity entity) {
+    void incr(const entt::registry &, entt::entity entity) {
         last = entity;
         ++counter;
     }
 
     template<typename Component>
-    void decr(entt::entity entity) {
+    void decr(const entt::registry &, entt::entity entity) {
         last = entity;
         --counter;
     }
@@ -1374,8 +1374,8 @@ TEST(Registry, Dependencies) {
     constexpr auto emplace_or_replace = &entt::registry::emplace_or_replace<double>;
     constexpr auto remove = &entt::registry::remove<double>;
 
-    registry.on_construct<int>().connect<emplace_or_replace>(registry);
-    registry.on_destroy<int>().connect<remove>(registry);
+    registry.on_construct<int>().connect<emplace_or_replace>();
+    registry.on_destroy<int>().connect<remove>();
     registry.emplace<double>(entity, .3);
 
     ASSERT_FALSE(registry.has<int>(entity));
@@ -1390,8 +1390,8 @@ TEST(Registry, Dependencies) {
 
     ASSERT_FALSE((registry.any<int, double>(entity)));
 
-    registry.on_construct<int>().disconnect<emplace_or_replace>(registry);
-    registry.on_destroy<int>().disconnect<remove>(registry);
+    registry.on_construct<int>().disconnect<emplace_or_replace>();
+    registry.on_destroy<int>().disconnect<remove>();
     registry.emplace<int>(entity);
 
     ASSERT_TRUE((registry.any<int, double>(entity)));
@@ -1400,7 +1400,7 @@ TEST(Registry, Dependencies) {
 
 TEST(Registry, StableEmplace) {
     entt::registry registry;
-    registry.on_construct<int>().connect<&listener::sort<int>>(registry);
+    registry.on_construct<int>().connect<&listener::sort<int>>();
     registry.emplace<int>(registry.create(), 0);
 
     ASSERT_EQ(registry.emplace<int>(registry.create(), 1), 1);