Ver Fonte

signals meet references (close #289)

Michele Caini há 6 anos atrás
pai
commit
1c7d9e3d75

+ 1 - 0
TODO

@@ -18,6 +18,7 @@
 * built-in support for dual (or N-) buffering
 * allow to "merge" registries easily
 * allow for custom stomp functions
+* deprecate/replace snapshot
 * remove prototype
 
 TODO

+ 4 - 5
docs/md/entity.md

@@ -348,13 +348,13 @@ notified on the creation of a component, use the `on_construct` member function:
 registry.on_construct<position>().connect<&my_free_function>();
 
 // connects a member function
-registry.on_construct<position>().connect<&my_class::member>(&instance);
+registry.on_construct<position>().connect<&my_class::member>(instance);
 
 // disconnects a free function
 registry.on_construct<position>().disconnect<&my_free_function>();
 
 // disconnects a member function
-registry.on_construct<position>().disconnect<&my_class::member>(&instance);
+registry.on_construct<position>().disconnect<&my_class::member>(instance);
 ```
 
 To be notified when components are destroyed, use the `on_destroy` member
@@ -656,9 +656,8 @@ brief, yet incomplete list of some of them:
   entity.<br/>
   Put aside the fact that having the prototypes separated from the simulation is
   useful in many cases, they make also the codebase easier to maintain, since
-  updating a template is much less error prone than jumping in the code to
-  update all the snippets copied and pasted around to initialize entities and
-  components.
+  updating a template is less error prone than jumping in the code to update all
+  the snippets copied and pasted around to initialize entities and components.
 
 * Literally _move_ entities from one registry to another (that is a copy
   followed by a destroy), which can be useful for solving problems such as the

+ 16 - 16
docs/md/signal.md

@@ -71,27 +71,27 @@ delegate.connect<&f>();
 
 // bind a member function to the delegate
 my_struct instance;
-delegate.connect<&my_struct::f>(&instance);
+delegate.connect<&my_struct::f>(instance);
 ```
 
 The delegate class accepts also data members, if needed. In this case, the
 function type of the delegate is such that the parameter list is empty and the
 value of the data member is at least convertible to the return type.
 
-Free functions having type equivalent to `void(T *, args...)` are accepted as
-well. In this case, `T *` is considered a payload and the function will receive
+Free functions having type equivalent to `void(T &, args...)` are accepted as
+well. In this case, `T &` is considered a payload and the function will receive
 it back every time it's invoked. In other terms, this works just fine with the
 above definition:
 
 ```cpp
-void g(const char *c, int i) { /* ... */ }
+void g(const char &c, int i) { /* ... */ }
 const char c = 'c';
 
-delegate.connect<&g>(&c);
+delegate.connect<&g>(c);
 delegate(42);
 ```
 
-The function `g` will be invoked with a pointer to `c` and `42`. However, the
+The function `g` will be invoked with a reference to `c` and `42`. However, the
 function type of the delegate is still `void(int)`. This is also the signature
 of its function call operator.
 
@@ -144,8 +144,8 @@ fine.
 
 # Signals
 
-Signal handlers work with naked pointers, function pointers and pointers to
-members. Listeners can be any kind of objects and users are in charge of
+Signal handlers work with references to classes, function pointers and pointers
+to members. Listeners can be any kind of objects and users are in charge of
 connecting and disconnecting them from a signal to avoid crashes due to
 different lifetimes. On the other side, performance shouldn't be affected that
 much by the presence of such a signal handler.<br/>
@@ -190,7 +190,7 @@ entt::sink sink{signal};
 listener instance;
 
 sink.connect<&foo>();
-sink.connect<&listener::bar>(&instance);
+sink.connect<&listener::bar>(instance);
 
 // ...
 
@@ -198,10 +198,10 @@ sink.connect<&listener::bar>(&instance);
 sink.disconnect<&foo>();
 
 // disconnect a member function of an instance
-sink.disconnect<&listener::bar>(&instance);
+sink.disconnect<&listener::bar>(instance);
 
 // disconnect all the member functions of an instance, if any
-sink.disconnect(&instance);
+sink.disconnect(instance);
 
 // discards all the listeners at once
 sink.disconnect();
@@ -280,7 +280,7 @@ This class shares part of its API with the one of the signal handler, but it
 doesn't require that all the types of events are specified when declared:
 
 ```cpp
-// define a general purpose dispatcher that works with naked pointers
+// define a general purpose dispatcher
 entt::dispatcher dispatcher{};
 ```
 
@@ -303,16 +303,16 @@ struct listener {
 // ...
 
 listener listener;
-dispatcher.sink<an_event>().connect<&listener::receive>(&listener);
-dispatcher.sink<another_event>().connect<&listener::method>(&listener);
+dispatcher.sink<an_event>().connect<&listener::receive>(listener);
+dispatcher.sink<another_event>().connect<&listener::method>(listener);
 ```
 
 The `disconnect` member function follows the same pattern and can be used to
 remove one listener at a time or all of them at once:
 
 ```cpp
-dispatcher.sink<an_event>().disconnect<&listener::receive>(&listener);
-dispatcher.sink<another_event>().disconnect(&listener);
+dispatcher.sink<an_event>().disconnect<&listener::receive>(listener);
+dispatcher.sink<another_event>().disconnect(listener);
 ```
 
 The `trigger` member function serves the purpose of sending an immediate event

+ 32 - 32
src/entt/entity/observer.hpp

@@ -173,72 +173,72 @@ class basic_observer {
     template<typename... Reject, typename... Require, typename AnyOf>
     struct matcher_handler<matcher<matcher<type_list<Reject...>, type_list<Require...>>, AnyOf>> {
         template<std::size_t Index>
-        static void maybe_valid_if(basic_observer *obs, const basic_registry<Entity> &reg, const Entity entt) {
+        static void maybe_valid_if(basic_observer &obs, const basic_registry<Entity> &reg, const Entity entt) {
             if(reg.template has<Require...>(entt) && !(reg.template has<Reject>(entt) || ...)) {
-                auto *comp = obs->view.try_get(entt);
-                (comp ? *comp : obs->view.construct(entt)) |= (1 << Index);
+                auto *comp = obs.view.try_get(entt);
+                (comp ? *comp : obs.view.construct(entt)) |= (1 << Index);
             }
         }
 
         template<std::size_t Index>
-        static void discard_if(basic_observer *obs, const basic_registry<Entity> &, const Entity entt) {
-            if(auto *value = obs->view.try_get(entt); value && !(*value &= (~(1 << Index)))) {
-                obs->view.destroy(entt);
+        static void discard_if(basic_observer &obs, const basic_registry<Entity> &, const Entity entt) {
+            if(auto *value = obs.view.try_get(entt); value && !(*value &= (~(1 << Index)))) {
+                obs.view.destroy(entt);
             }
         }
 
         template<std::size_t Index>
         static void connect(basic_observer &obs, basic_registry<Entity> &reg) {
-            (reg.template on_destroy<Require>().template connect<&discard_if<Index>>(&obs), ...);
-            (reg.template on_construct<Reject>().template connect<&discard_if<Index>>(&obs), ...);
-            reg.template on_replace<AnyOf>().template connect<&maybe_valid_if<Index>>(&obs);
-            reg.template on_destroy<AnyOf>().template connect<&discard_if<Index>>(&obs);
+            (reg.template on_destroy<Require>().template connect<&discard_if<Index>>(obs), ...);
+            (reg.template on_construct<Reject>().template connect<&discard_if<Index>>(obs), ...);
+            reg.template on_replace<AnyOf>().template connect<&maybe_valid_if<Index>>(obs);
+            reg.template on_destroy<AnyOf>().template connect<&discard_if<Index>>(obs);
         }
 
         static void disconnect(basic_observer &obs, basic_registry<Entity> &reg) {
-            (reg.template on_destroy<Require>().disconnect(&obs), ...);
-            (reg.template on_construct<Reject>().disconnect(&obs), ...);
-            reg.template on_replace<AnyOf>().disconnect(&obs);
-            reg.template on_destroy<AnyOf>().disconnect(&obs);
+            (reg.template on_destroy<Require>().disconnect(obs), ...);
+            (reg.template on_construct<Reject>().disconnect(obs), ...);
+            reg.template on_replace<AnyOf>().disconnect(obs);
+            reg.template on_destroy<AnyOf>().disconnect(obs);
         }
     };
 
     template<typename... Reject, typename... Require, typename... NoneOf, typename... AllOf>
     struct matcher_handler<matcher<matcher<type_list<Reject...>, type_list<Require...>>, type_list<NoneOf...>, type_list<AllOf...>>> {
         template<std::size_t Index>
-        static void maybe_valid_if(basic_observer *obs, const basic_registry<Entity> &reg, const Entity entt) {
+        static void maybe_valid_if(basic_observer &obs, const basic_registry<Entity> &reg, const Entity entt) {
             if(reg.template has<AllOf...>(entt) && !(reg.template has<NoneOf>(entt) || ...)
                     && reg.template has<Require...>(entt) && !(reg.template has<Reject>(entt) || ...))
             {
-                auto *comp = obs->view.try_get(entt);
-                (comp ? *comp : obs->view.construct(entt)) |= (1 << Index);
+                auto *comp = obs.view.try_get(entt);
+                (comp ? *comp : obs.view.construct(entt)) |= (1 << Index);
             }
         }
 
         template<std::size_t Index>
-        static void discard_if(basic_observer *obs, const basic_registry<Entity> &, const Entity entt) {
-            if(auto *value = obs->view.try_get(entt); value && !(*value &= (~(1 << Index)))) {
-                obs->view.destroy(entt);
+        static void discard_if(basic_observer &obs, const basic_registry<Entity> &, const Entity entt) {
+            if(auto *value = obs.view.try_get(entt); value && !(*value &= (~(1 << Index)))) {
+                obs.view.destroy(entt);
             }
         }
 
         template<std::size_t Index>
         static void connect(basic_observer &obs, basic_registry<Entity> &reg) {
-            (reg.template on_destroy<Require>().template connect<&discard_if<Index>>(&obs), ...);
-            (reg.template on_construct<Reject>().template connect<&discard_if<Index>>(&obs), ...);
-            (reg.template on_construct<AllOf>().template connect<&maybe_valid_if<Index>>(&obs), ...);
-            (reg.template on_destroy<NoneOf>().template connect<&maybe_valid_if<Index>>(&obs), ...);
-            (reg.template on_destroy<AllOf>().template connect<&discard_if<Index>>(&obs), ...);
-            (reg.template on_construct<NoneOf>().template connect<&discard_if<Index>>(&obs), ...);
+            (reg.template on_destroy<Require>().template connect<&discard_if<Index>>(obs), ...);
+            (reg.template on_construct<Reject>().template connect<&discard_if<Index>>(obs), ...);
+            (reg.template on_construct<AllOf>().template connect<&maybe_valid_if<Index>>(obs), ...);
+            (reg.template on_destroy<NoneOf>().template connect<&maybe_valid_if<Index>>(obs), ...);
+            (reg.template on_destroy<AllOf>().template connect<&discard_if<Index>>(obs), ...);
+            (reg.template on_construct<NoneOf>().template connect<&discard_if<Index>>(obs), ...);
         }
 
         static void disconnect(basic_observer &obs, basic_registry<Entity> &reg) {
-            (reg.template on_destroy<Require>().disconnect(&obs), ...);
-            (reg.template on_construct<Reject>().disconnect(&obs), ...);
-            (reg.template on_construct<AllOf>().disconnect(&obs), ...);
-            (reg.template on_destroy<NoneOf>().disconnect(&obs), ...);
-            (reg.template on_destroy<AllOf>().disconnect(&obs), ...);
-            (reg.template on_construct<NoneOf>().disconnect(&obs), ...);
+            (reg.template on_destroy<Require>().disconnect(obs), ...);
+            (reg.template on_construct<Reject>().disconnect(obs), ...);
+            (reg.template on_construct<AllOf>().disconnect(obs), ...);
+            (reg.template on_destroy<NoneOf>().disconnect(obs), ...);
+            (reg.template on_destroy<AllOf>().disconnect(obs), ...);
+            (reg.template on_construct<NoneOf>().disconnect(obs), ...);
         }
     };
 

+ 6 - 6
src/entt/entity/registry.hpp

@@ -1347,14 +1347,14 @@ public:
             ENTT_ASSERT((!std::get<pool_type<Owned> *>(curr->cpools)->group && ...));
 
             ((std::get<pool_type<Owned> *>(curr->cpools)->group = curr), ...);
-            (std::get<pool_type<Owned> *>(curr->cpools)->on_construct().template connect<&handler_type::template maybe_valid_if<Owned>>(curr), ...);
-            (std::get<pool_type<Owned> *>(curr->cpools)->on_destroy().template connect<&handler_type::discard_if>(curr), ...);
+            (std::get<pool_type<Owned> *>(curr->cpools)->on_construct().template connect<&handler_type::template maybe_valid_if<Owned>>(*curr), ...);
+            (std::get<pool_type<Owned> *>(curr->cpools)->on_destroy().template connect<&handler_type::discard_if>(*curr), ...);
 
-            (std::get<pool_type<Get> *>(curr->cpools)->on_construct().template connect<&handler_type::template maybe_valid_if<Get>>(curr), ...);
-            (std::get<pool_type<Get> *>(curr->cpools)->on_destroy().template connect<&handler_type::discard_if>(curr), ...);
+            (std::get<pool_type<Get> *>(curr->cpools)->on_construct().template connect<&handler_type::template maybe_valid_if<Get>>(*curr), ...);
+            (std::get<pool_type<Get> *>(curr->cpools)->on_destroy().template connect<&handler_type::discard_if>(*curr), ...);
 
-            (std::get<pool_type<Exclude> *>(curr->cpools)->on_destroy().template connect<&handler_type::template maybe_valid_if<Exclude>>(curr), ...);
-            (std::get<pool_type<Exclude> *>(curr->cpools)->on_construct().template connect<&handler_type::discard_if>(curr), ...);
+            (std::get<pool_type<Exclude> *>(curr->cpools)->on_destroy().template connect<&handler_type::template maybe_valid_if<Exclude>>(*curr), ...);
+            (std::get<pool_type<Exclude> *>(curr->cpools)->on_construct().template connect<&handler_type::discard_if>(*curr), ...);
 
             const auto *cpool = std::min({
                 static_cast<sparse_set<Entity> *>(std::get<pool_type<Owned> *>(curr->cpools))...,

+ 17 - 16
src/entt/signal/delegate.hpp

@@ -27,20 +27,20 @@ template<typename Ret, typename... Args>
 auto to_function_pointer(Ret(*)(Args...)) -> Ret(*)(Args...);
 
 
-template<typename Ret, typename... Args, typename Type, typename Payload, typename = std::enable_if_t<std::is_convertible_v<Payload *, Type *>>>
-auto to_function_pointer(Ret(*)(Type *, Args...), Payload *) -> Ret(*)(Args...);
+template<typename Ret, typename... Args, typename Type, typename Payload, typename = std::enable_if_t<std::is_convertible_v<Payload &, Type &>>>
+auto to_function_pointer(Ret(*)(Type &, Args...), Payload &) -> Ret(*)(Args...);
 
 
 template<typename Class, typename Ret, typename... Args>
-auto to_function_pointer(Ret(Class:: *)(Args...), const Class *) -> Ret(*)(Args...);
+auto to_function_pointer(Ret(Class:: *)(Args...), const Class &) -> Ret(*)(Args...);
 
 
 template<typename Class, typename Ret, typename... Args>
-auto to_function_pointer(Ret(Class:: *)(Args...) const, const Class *) -> Ret(*)(Args...);
+auto to_function_pointer(Ret(Class:: *)(Args...) const, const Class &) -> Ret(*)(Args...);
 
 
 template<typename Class, typename Type>
-auto to_function_pointer(Type Class:: *, const Class *) -> Type(*)();
+auto to_function_pointer(Type Class:: *, const Class &) -> Type(*)();
 
 
 template<typename>
@@ -115,9 +115,9 @@ class delegate<Ret(Args...)> {
     }
 
     template<auto Candidate, typename Type, std::size_t... Index>
-    void connect(Type *value_or_instance, std::index_sequence<Index...>) ENTT_NOEXCEPT {
-        static_assert(std::is_invocable_r_v<Ret, decltype(Candidate), Type *, std::tuple_element_t<Index, std::tuple<Args...>>...>);
-        data = value_or_instance;
+    void connect(Type &value_or_instance, std::index_sequence<Index...>) ENTT_NOEXCEPT {
+        static_assert(std::is_invocable_r_v<Ret, decltype(Candidate), Type &, std::tuple_element_t<Index, std::tuple<Args...>>...>);
+        data = &value_or_instance;
 
         fn = [](const void *payload, std::tuple<Args &&...> args) -> Ret {
             Type *curr = nullptr;
@@ -129,7 +129,7 @@ class delegate<Ret(Args...)> {
             }
 
             // Ret(...) makes void(...) eat the return values to avoid errors
-            return Ret(std::invoke(Candidate, curr, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(args))...));
+            return Ret(std::invoke(Candidate, *curr, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(args))...));
         };
     }
 
@@ -158,10 +158,10 @@ public:
      * or a free function with payload.
      * @tparam Candidate Member or free function to connect to the delegate.
      * @tparam Type Type of class or type of payload.
-     * @param value_or_instance A valid pointer that fits the purpose.
+     * @param value_or_instance A valid reference that fits the purpose.
      */
     template<auto Candidate, typename Type>
-    delegate(connect_arg_t<Candidate>, Type *value_or_instance) ENTT_NOEXCEPT
+    delegate(connect_arg_t<Candidate>, Type &value_or_instance) ENTT_NOEXCEPT
         : delegate{}
     {
         connect<Candidate>(value_or_instance);
@@ -190,11 +190,11 @@ public:
      *
      * @tparam Candidate Member or free function to connect to the delegate.
      * @tparam Type Type of class or type of payload.
-     * @param value_or_instance A valid pointer that fits the purpose.
+     * @param value_or_instance A valid reference that fits the purpose.
      */
     template<auto Candidate, typename Type>
-    void connect(Type *value_or_instance) ENTT_NOEXCEPT {
-        constexpr auto extent = internal::function_extent_v<decltype(internal::to_function_pointer(std::declval<decltype(Candidate)>(), std::declval<Type *>()))>;
+    void connect(Type &value_or_instance) ENTT_NOEXCEPT {
+        constexpr auto extent = internal::function_extent_v<decltype(internal::to_function_pointer(std::declval<decltype(Candidate)>(), value_or_instance))>;
         connect<Candidate>(value_or_instance, std::make_index_sequence<extent>{});
     }
 
@@ -292,12 +292,13 @@ delegate(connect_arg_t<Function>) ENTT_NOEXCEPT
  * It allows to deduce the function type of the delegate directly from a member
  * or a free function with payload provided to the constructor.
  *
+ * @param value_or_instance A valid reference that fits the purpose.
  * @tparam Candidate Member or free function to connect to the delegate.
  * @tparam Type Type of class or type of payload.
  */
 template<auto Candidate, typename Type>
-delegate(connect_arg_t<Candidate>, Type *) ENTT_NOEXCEPT
--> delegate<std::remove_pointer_t<decltype(internal::to_function_pointer(Candidate, std::declval<Type *>()))>>;
+delegate(connect_arg_t<Candidate>, Type &value_or_instance) ENTT_NOEXCEPT
+-> delegate<std::remove_pointer_t<decltype(internal::to_function_pointer(Candidate, value_or_instance))>>;
 
 
 }

+ 3 - 3
src/entt/signal/dispatcher.hpp

@@ -24,9 +24,9 @@ namespace entt {
  * type `Event`, listeners are such that they can be invoked with an argument of
  * type `const Event &`, no matter what the return type is.
  *
- * The type of the instances is `Class *` (a naked pointer). It means that users
- * must guarantee that the lifetimes of the instances overcome the one of the
- * dispatcher itself to avoid crashes.
+ * The types of the instances are `Class &`. Users must guarantee that the
+ * lifetimes of the objects overcome the one of the dispatcher itself to avoid
+ * crashes.
  */
 class dispatcher {
     using event_family = family<struct internal_dispatcher_event_family>;

+ 14 - 12
src/entt/signal/sigh.hpp

@@ -42,9 +42,9 @@ class sigh;
 /**
  * @brief Unmanaged signal handler.
  *
- * It works directly with naked pointers to classes and pointers to member
- * functions as well as pointers to free functions. Users of this class are in
- * charge of disconnecting instances before deleting them.
+ * It works directly with references to classes and pointers to member functions
+ * as well as pointers to free functions. Users of this class are in charge of
+ * disconnecting instances before deleting them.
  *
  * This class serves mainly two purposes:
  *
@@ -305,7 +305,7 @@ class sink<Ret(Args...)> {
     using signal_type = sigh<Ret(Args...)>;
 
     template<auto Candidate, typename Type>
-    static void release(Type *value_or_instance, void *signal) {
+    static void release(Type &value_or_instance, void *signal) {
         sink{*static_cast<signal_type *>(signal)}.disconnect<Candidate>(value_or_instance);
     }
 
@@ -363,11 +363,11 @@ public:
      *
      * @tparam Candidate Member or free function to connect to the signal.
      * @tparam Type Type of class or type of payload.
-     * @param value_or_instance A valid pointer that fits the purpose.
+     * @param value_or_instance A valid reference that fits the purpose.
      * @return A properly initialized connection object.
      */
     template<auto Candidate, typename Type>
-    connection connect(Type *value_or_instance) {
+    connection connect(Type &value_or_instance) {
         disconnect<Candidate>(value_or_instance);
         delegate<void(void *)> conn{};
         conn.template connect<&sink::release<Candidate, Type>>(value_or_instance);
@@ -392,10 +392,10 @@ public:
      * a signal.
      * @tparam Candidate Member or free function to disconnect from the signal.
      * @tparam Type Type of class or type of payload.
-     * @param value_or_instance A valid pointer that fits the purpose.
+     * @param value_or_instance A valid reference that fits the purpose.
      */
     template<auto Candidate, typename Type>
-    void disconnect(Type *value_or_instance) {
+    void disconnect(Type &value_or_instance) {
         auto &calls = signal->calls;
         delegate<Ret(Args...)> delegate{};
         delegate.template connect<Candidate>(value_or_instance);
@@ -405,12 +405,14 @@ public:
     /**
      * @brief Disconnects member functions or free functions based on an
      * instance or specific payload.
-     * @param value_or_instance A valid pointer that fits the purpose.
+     * @tparam Type Type of class or type of payload.
+     * @param value_or_instance A valid reference that fits the purpose.
      */
-    void disconnect(const void *value_or_instance) {
+    template<typename Type>
+    void disconnect(const Type &value_or_instance) {
         auto &calls = signal->calls;
-        calls.erase(std::remove_if(calls.begin(), calls.end(), [value_or_instance](const auto &delegate) {
-            return value_or_instance == delegate.instance();
+        calls.erase(std::remove_if(calls.begin(), calls.end(), [&value_or_instance](const auto &delegate) {
+            return delegate.instance() == &value_or_instance;
         }), calls.end());
     }
 

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

@@ -925,10 +925,10 @@ TEST(Registry, Signals) {
     entt::registry registry;
     listener listener;
 
-    registry.on_construct<empty_type>().connect<&listener::incr<empty_type>>(&listener);
-    registry.on_destroy<empty_type>().connect<&listener::decr<empty_type>>(&listener);
-    registry.on_construct<int>().connect<&listener::incr<int>>(&listener);
-    registry.on_destroy<int>().connect<&listener::decr<int>>(&listener);
+    registry.on_construct<empty_type>().connect<&listener::incr<empty_type>>(listener);
+    registry.on_destroy<empty_type>().connect<&listener::decr<empty_type>>(listener);
+    registry.on_construct<int>().connect<&listener::incr<int>>(listener);
+    registry.on_destroy<int>().connect<&listener::decr<int>>(listener);
 
     auto e0 = registry.create();
     auto e1 = registry.create();
@@ -951,8 +951,8 @@ TEST(Registry, Signals) {
     ASSERT_EQ(listener.counter, 2);
     ASSERT_EQ(listener.last, e0);
 
-    registry.on_destroy<empty_type>().disconnect<&listener::decr<empty_type>>(&listener);
-    registry.on_destroy<int>().disconnect<&listener::decr<int>>(&listener);
+    registry.on_destroy<empty_type>().disconnect<&listener::decr<empty_type>>(listener);
+    registry.on_destroy<int>().disconnect<&listener::decr<int>>(listener);
 
     registry.remove<empty_type>(e1);
     registry.remove<int>(e1);
@@ -960,8 +960,8 @@ TEST(Registry, Signals) {
     ASSERT_EQ(listener.counter, 2);
     ASSERT_EQ(listener.last, e0);
 
-    registry.on_construct<empty_type>().disconnect<&listener::incr<empty_type>>(&listener);
-    registry.on_construct<int>().disconnect<&listener::incr<int>>(&listener);
+    registry.on_construct<empty_type>().disconnect<&listener::incr<empty_type>>(listener);
+    registry.on_construct<int>().disconnect<&listener::incr<int>>(listener);
 
     registry.assign<empty_type>(e1);
     registry.assign<int>(e1);
@@ -969,8 +969,8 @@ TEST(Registry, Signals) {
     ASSERT_EQ(listener.counter, 2);
     ASSERT_EQ(listener.last, e0);
 
-    registry.on_construct<int>().connect<&listener::incr<int>>(&listener);
-    registry.on_destroy<int>().connect<&listener::decr<int>>(&listener);
+    registry.on_construct<int>().connect<&listener::incr<int>>(listener);
+    registry.on_destroy<int>().connect<&listener::decr<int>>(listener);
 
     registry.assign<int>(e0);
     registry.reset<int>(e1);
@@ -978,8 +978,8 @@ TEST(Registry, Signals) {
     ASSERT_EQ(listener.counter, 2);
     ASSERT_EQ(listener.last, e1);
 
-    registry.on_construct<empty_type>().connect<&listener::incr<empty_type>>(&listener);
-    registry.on_destroy<empty_type>().connect<&listener::decr<empty_type>>(&listener);
+    registry.on_construct<empty_type>().connect<&listener::incr<empty_type>>(listener);
+    registry.on_destroy<empty_type>().connect<&listener::decr<empty_type>>(listener);
 
     registry.reset<empty_type>(e1);
     registry.assign<empty_type>(e0);
@@ -1011,8 +1011,8 @@ TEST(Registry, Signals) {
     ASSERT_EQ(listener.counter, 2);
     ASSERT_EQ(listener.last, e0);
 
-    registry.on_destroy<empty_type>().disconnect<&listener::decr<empty_type>>(&listener);
-    registry.on_destroy<int>().disconnect<&listener::decr<int>>(&listener);
+    registry.on_destroy<empty_type>().disconnect<&listener::decr<empty_type>>(listener);
+    registry.on_destroy<int>().disconnect<&listener::decr<int>>(listener);
 
     registry.assign_or_replace<empty_type>(e0);
     registry.assign_or_replace<int>(e0);
@@ -1020,8 +1020,8 @@ TEST(Registry, Signals) {
     ASSERT_EQ(listener.counter, 2);
     ASSERT_EQ(listener.last, e0);
 
-    registry.on_replace<empty_type>().connect<&listener::incr<empty_type>>(&listener);
-    registry.on_replace<int>().connect<&listener::incr<int>>(&listener);
+    registry.on_replace<empty_type>().connect<&listener::incr<empty_type>>(listener);
+    registry.on_replace<int>().connect<&listener::incr<int>>(listener);
 
     registry.assign_or_replace<empty_type>(e0);
     registry.assign_or_replace<int>(e0);
@@ -1179,13 +1179,13 @@ TEST(Registry, CreateManyEntitiesWithComponentsAtOnceWithListener) {
     entt::entity entities[3];
     listener listener;
 
-    registry.on_construct<int>().connect<&listener::incr<int>>(&listener);
+    registry.on_construct<int>().connect<&listener::incr<int>>(listener);
     registry.create<int, char>(std::begin(entities), std::end(entities));
 
     ASSERT_EQ(listener.counter, 3);
 
-    registry.on_construct<int>().disconnect<&listener::incr<int>>(&listener);
-    registry.on_construct<empty_type>().connect<&listener::incr<empty_type>>(&listener);
+    registry.on_construct<int>().disconnect<&listener::incr<int>>(listener);
+    registry.on_construct<empty_type>().connect<&listener::incr<empty_type>>(listener);
     registry.create<char, empty_type>(std::begin(entities), std::end(entities));
 
     ASSERT_EQ(listener.counter, 6);

+ 36 - 36
test/entt/signal/delegate.cpp

@@ -6,8 +6,8 @@ int delegate_function(const int &i) {
     return i*i;
 }
 
-int curried_function(const int *i, int j) {
-    return *i+j;
+int curried_function(const int &i, int j) {
+    return i+j;
 }
 
 int non_const_reference(int &i) {
@@ -51,7 +51,7 @@ TEST(Delegate, Functionalities) {
     ASSERT_EQ(ff_del, mf_del);
 
     ff_del.connect<&delegate_function>();
-    mf_del.connect<&delegate_functor::operator()>(&functor);
+    mf_del.connect<&delegate_functor::operator()>(functor);
 
     ASSERT_TRUE(ff_del);
     ASSERT_TRUE(mf_del);
@@ -82,7 +82,7 @@ TEST(Delegate, DataMembers) {
     entt::delegate<double()> delegate;
     delegate_functor functor;
 
-    delegate.connect<&delegate_functor::data_member>(&functor);
+    delegate.connect<&delegate_functor::data_member>(functor);
 
     ASSERT_EQ(delegate(), 42);
 }
@@ -113,37 +113,37 @@ TEST(Delegate, Comparison) {
     ASSERT_TRUE(lhs == rhs);
     ASSERT_EQ(lhs, rhs);
 
-    lhs.connect<&curried_function>(&value);
+    lhs.connect<&curried_function>(value);
 
-    ASSERT_EQ(lhs, (entt::delegate<int(int)>{entt::connect_arg<&curried_function>, &value}));
+    ASSERT_EQ(lhs, (entt::delegate<int(int)>{entt::connect_arg<&curried_function>, value}));
     ASSERT_TRUE(lhs != rhs);
     ASSERT_FALSE(lhs == rhs);
     ASSERT_NE(lhs, rhs);
 
-    rhs.connect<&curried_function>(&value);
+    rhs.connect<&curried_function>(value);
 
-    ASSERT_EQ(rhs, (entt::delegate<int(int)>{entt::connect_arg<&curried_function>, &value}));
+    ASSERT_EQ(rhs, (entt::delegate<int(int)>{entt::connect_arg<&curried_function>, value}));
     ASSERT_FALSE(lhs != rhs);
     ASSERT_TRUE(lhs == rhs);
     ASSERT_EQ(lhs, rhs);
 
-    lhs.connect<&delegate_functor::operator()>(&functor);
+    lhs.connect<&delegate_functor::operator()>(functor);
 
-    ASSERT_EQ(lhs, (entt::delegate<int(int)>{entt::connect_arg<&delegate_functor::operator()>, &functor}));
+    ASSERT_EQ(lhs, (entt::delegate<int(int)>{entt::connect_arg<&delegate_functor::operator()>, functor}));
     ASSERT_TRUE(lhs != rhs);
     ASSERT_FALSE(lhs == rhs);
     ASSERT_NE(lhs, rhs);
 
-    rhs.connect<&delegate_functor::operator()>(&functor);
+    rhs.connect<&delegate_functor::operator()>(functor);
 
-    ASSERT_EQ(rhs, (entt::delegate<int(int)>{entt::connect_arg<&delegate_functor::operator()>, &functor}));
+    ASSERT_EQ(rhs, (entt::delegate<int(int)>{entt::connect_arg<&delegate_functor::operator()>, functor}));
     ASSERT_FALSE(lhs != rhs);
     ASSERT_TRUE(lhs == rhs);
     ASSERT_EQ(lhs, rhs);
 
-    lhs.connect<&delegate_functor::operator()>(&other);
+    lhs.connect<&delegate_functor::operator()>(other);
 
-    ASSERT_EQ(lhs, (entt::delegate<int(int)>{entt::connect_arg<&delegate_functor::operator()>, &other}));
+    ASSERT_EQ(lhs, (entt::delegate<int(int)>{entt::connect_arg<&delegate_functor::operator()>, other}));
     ASSERT_NE(lhs.instance(), rhs.instance());
     ASSERT_TRUE(lhs != rhs);
     ASSERT_FALSE(lhs == rhs);
@@ -168,16 +168,16 @@ TEST(Delegate, ConstNonConstNoExcept) {
     entt::delegate<void()> delegate;
     const_nonconst_noexcept functor;
 
-    delegate.connect<&const_nonconst_noexcept::f>(&functor);
+    delegate.connect<&const_nonconst_noexcept::f>(functor);
     delegate();
 
-    delegate.connect<&const_nonconst_noexcept::g>(&functor);
+    delegate.connect<&const_nonconst_noexcept::g>(functor);
     delegate();
 
-    delegate.connect<&const_nonconst_noexcept::h>(&functor);
+    delegate.connect<&const_nonconst_noexcept::h>(functor);
     delegate();
 
-    delegate.connect<&const_nonconst_noexcept::i>(&functor);
+    delegate.connect<&const_nonconst_noexcept::i>(functor);
     delegate();
 
     ASSERT_EQ(functor.cnt, 4);
@@ -188,17 +188,17 @@ TEST(Delegate, DeductionGuide) {
     int value = 0;
 
     entt::delegate func{entt::connect_arg<&delegate_function>};
-    entt::delegate curried_func{entt::connect_arg<&curried_function>, &value};
-    entt::delegate curried_func_const{entt::connect_arg<&curried_function>, &std::as_const(value)};
-    entt::delegate member_func_f{entt::connect_arg<&const_nonconst_noexcept::f>, &functor};
-    entt::delegate member_func_g{entt::connect_arg<&const_nonconst_noexcept::g>, &functor};
-    entt::delegate member_func_h{entt::connect_arg<&const_nonconst_noexcept::h>, &functor};
-    entt::delegate member_func_h_const{entt::connect_arg<&const_nonconst_noexcept::h>, &std::as_const(functor)};
-    entt::delegate member_func_i{entt::connect_arg<&const_nonconst_noexcept::i>, &functor};
-    entt::delegate member_func_i_const{entt::connect_arg<&const_nonconst_noexcept::i>, &std::as_const(functor)};
-    entt::delegate data_member_u{entt::connect_arg<&const_nonconst_noexcept::u>, &functor};
-    entt::delegate data_member_v{entt::connect_arg<&const_nonconst_noexcept::v>, &functor};
-    entt::delegate data_member_v_const{entt::connect_arg<&const_nonconst_noexcept::v>, &std::as_const(functor)};
+    entt::delegate curried_func{entt::connect_arg<&curried_function>, value};
+    entt::delegate curried_func_const{entt::connect_arg<&curried_function>, std::as_const(value)};
+    entt::delegate member_func_f{entt::connect_arg<&const_nonconst_noexcept::f>, functor};
+    entt::delegate member_func_g{entt::connect_arg<&const_nonconst_noexcept::g>, functor};
+    entt::delegate member_func_h{entt::connect_arg<&const_nonconst_noexcept::h>, functor};
+    entt::delegate member_func_h_const{entt::connect_arg<&const_nonconst_noexcept::h>, std::as_const(functor)};
+    entt::delegate member_func_i{entt::connect_arg<&const_nonconst_noexcept::i>, functor};
+    entt::delegate member_func_i_const{entt::connect_arg<&const_nonconst_noexcept::i>, std::as_const(functor)};
+    entt::delegate data_member_u{entt::connect_arg<&const_nonconst_noexcept::u>, functor};
+    entt::delegate data_member_v{entt::connect_arg<&const_nonconst_noexcept::v>, functor};
+    entt::delegate data_member_v_const{entt::connect_arg<&const_nonconst_noexcept::v>, std::as_const(functor)};
 
     static_assert(std::is_same_v<typename decltype(func)::function_type, int(const int &)>);
     static_assert(std::is_same_v<typename decltype(curried_func)::function_type, int(int)>);
@@ -233,7 +233,7 @@ TEST(Delegate, ConstInstance) {
 
     ASSERT_FALSE(delegate);
 
-    delegate.connect<&delegate_functor::identity>(&functor);
+    delegate.connect<&delegate_functor::identity>(functor);
 
     ASSERT_TRUE(delegate);
     ASSERT_EQ(delegate(3), 3);
@@ -266,7 +266,7 @@ TEST(Delegate, CurriedFunction) {
     entt::delegate<int(int)> delegate;
     const auto value = 3;
 
-    delegate.connect<&curried_function>(&value);
+    delegate.connect<&curried_function>(value);
 
     ASSERT_TRUE(delegate);
     ASSERT_EQ(delegate(1), 4);
@@ -278,8 +278,8 @@ TEST(Delegate, Constructors) {
 
     entt::delegate<int(int)> empty{};
     entt::delegate<int(int)> func{entt::connect_arg<&delegate_function>};
-    entt::delegate<int(int)> curr{entt::connect_arg<&curried_function>, &value};
-    entt::delegate<int(int)> member{entt::connect_arg<&delegate_functor::operator()>, &functor};
+    entt::delegate<int(int)> curr{entt::connect_arg<&curried_function>, value};
+    entt::delegate<int(int)> member{entt::connect_arg<&delegate_functor::operator()>, functor};
 
     ASSERT_FALSE(empty);
 
@@ -297,8 +297,8 @@ TEST(Delegate, VoidVsNonVoidReturnType) {
     delegate_functor functor;
 
     entt::delegate<void(int)> func{entt::connect_arg<&delegate_function>};
-    entt::delegate<void(int)> member{entt::connect_arg<&delegate_functor::operator()>, &functor};
-    entt::delegate<void(int)> cmember{entt::connect_arg<&delegate_functor::identity>, &std::as_const(functor)};
+    entt::delegate<void(int)> member{entt::connect_arg<&delegate_functor::operator()>, functor};
+    entt::delegate<void(int)> cmember{entt::connect_arg<&delegate_functor::identity>, std::as_const(functor)};
 
     ASSERT_TRUE(func);
     ASSERT_TRUE(member);
@@ -315,7 +315,7 @@ TEST(Delegate, TheLessTheBetter) {
     ASSERT_EQ(delegate(3, 'c'), 9);
 
     // int delegate_functor::operator()(int);
-    delegate.connect<&delegate_functor::operator()>(&functor);
+    delegate.connect<&delegate_functor::operator()>(functor);
 
     ASSERT_EQ(delegate(3, 'c'), 6);
 }

+ 2 - 2
test/entt/signal/dispatcher.cpp

@@ -23,7 +23,7 @@ TEST(Dispatcher, Functionalities) {
     dispatcher.enqueue<one_more_event>();
     dispatcher.update<one_more_event>();
 
-    dispatcher.sink<an_event>().connect<&receiver::receive>(&receiver);
+    dispatcher.sink<an_event>().connect<&receiver::receive>(receiver);
     dispatcher.trigger<an_event>();
     dispatcher.enqueue<an_event>();
 
@@ -43,7 +43,7 @@ TEST(Dispatcher, Functionalities) {
 
     an_event event{};
 
-    dispatcher.sink<an_event>().disconnect<&receiver::receive>(&receiver);
+    dispatcher.sink<an_event>().disconnect<&receiver::receive>(receiver);
     dispatcher.trigger<an_event>();
     dispatcher.enqueue(event);
     dispatcher.update();

+ 21 - 30
test/entt/signal/sigh.cpp

@@ -96,43 +96,34 @@ TEST(SigH, Functions) {
     ASSERT_TRUE(sigh.empty());
     ASSERT_EQ(static_cast<entt::sigh<void(int &)>::size_type>(0), sigh.size());
     ASSERT_EQ(v, 0);
-
-    sink.connect<&sigh_listener::f>();
-
-    ASSERT_FALSE(sigh.empty());
-    ASSERT_EQ(static_cast<entt::sigh<void(int &)>::size_type>(1), sigh.size());
-
-    sink.disconnect(nullptr);
-
-    ASSERT_TRUE(sigh.empty());
-    ASSERT_EQ(static_cast<entt::sigh<void(int &)>::size_type>(0), sigh.size());}
+}
 
 TEST(SigH, Members) {
     sigh_listener l1, l2;
     entt::sigh<bool(int)> sigh;
     entt::sink sink{sigh};
 
-    sink.connect<&sigh_listener::g>(&l1);
+    sink.connect<&sigh_listener::g>(l1);
     sigh.publish(42);
 
     ASSERT_TRUE(l1.k);
     ASSERT_FALSE(sigh.empty());
     ASSERT_EQ(static_cast<entt::sigh<bool(int)>::size_type>(1), sigh.size());
 
-    sink.disconnect<&sigh_listener::g>(&l1);
+    sink.disconnect<&sigh_listener::g>(l1);
     sigh.publish(42);
 
     ASSERT_TRUE(l1.k);
     ASSERT_TRUE(sigh.empty());
     ASSERT_EQ(static_cast<entt::sigh<bool(int)>::size_type>(0), sigh.size());
 
-    sink.connect<&sigh_listener::g>(&l1);
-    sink.connect<&sigh_listener::h>(&l2);
+    sink.connect<&sigh_listener::g>(l1);
+    sink.connect<&sigh_listener::h>(l2);
 
     ASSERT_FALSE(sigh.empty());
     ASSERT_EQ(static_cast<entt::sigh<bool(int)>::size_type>(2), sigh.size());
 
-    sink.disconnect(&l1);
+    sink.disconnect(l1);
 
     ASSERT_FALSE(sigh.empty());
     ASSERT_EQ(static_cast<entt::sigh<bool(int)>::size_type>(1), sigh.size());
@@ -144,8 +135,8 @@ TEST(SigH, Collector) {
     entt::sink sink{sigh};
     int cnt = 0;
 
-    sink.connect<&sigh_listener::g>(&listener);
-    sink.connect<&sigh_listener::h>(&listener);
+    sink.connect<&sigh_listener::g>(listener);
+    sink.connect<&sigh_listener::h>(listener);
 
     listener.k = true;
     sigh.collect([&listener, &cnt](bool value) {
@@ -174,8 +165,8 @@ TEST(SigH, CollectorVoid) {
     entt::sink sink{sigh};
     int cnt = 0;
 
-    sink.connect<&sigh_listener::g>(&listener);
-    sink.connect<&sigh_listener::h>(&listener);
+    sink.connect<&sigh_listener::g>(listener);
+    sink.connect<&sigh_listener::h>(listener);
     sigh.collect([&cnt]() { ++cnt; }, 42);
 
     ASSERT_FALSE(sigh.empty());
@@ -219,7 +210,7 @@ TEST(SigH, ScopedConnection) {
     {
         ASSERT_FALSE(listener.k);
 
-        entt::scoped_connection conn = sink.connect<&sigh_listener::g>(&listener);
+        entt::scoped_connection conn = sink.connect<&sigh_listener::g>(listener);
         sigh.publish(42);
 
         ASSERT_FALSE(sigh.empty());
@@ -244,7 +235,7 @@ TEST(SigH, ScopedConnectionConstructorsAndOperators) {
         ASSERT_FALSE(conn);
 
         entt::scoped_connection inner{};
-        inner = sink.connect<&sigh_listener::g>(&listener);
+        inner = sink.connect<&sigh_listener::g>(listener);
         sigh.publish(42);
 
         ASSERT_FALSE(sigh.empty());
@@ -256,7 +247,7 @@ TEST(SigH, ScopedConnectionConstructorsAndOperators) {
         ASSERT_TRUE(sigh.empty());
         ASSERT_FALSE(inner);
 
-        auto basic = sink.connect<&sigh_listener::g>(&listener);
+        auto basic = sink.connect<&sigh_listener::g>(listener);
         inner = std::as_const(basic);
         sigh.publish(42);
 
@@ -285,19 +276,19 @@ TEST(SigH, ConstNonConstNoExcept) {
     const_nonconst_noexcept functor;
     const const_nonconst_noexcept cfunctor;
 
-    sink.connect<&const_nonconst_noexcept::f>(&functor);
-    sink.connect<&const_nonconst_noexcept::g>(&functor);
-    sink.connect<&const_nonconst_noexcept::h>(&cfunctor);
-    sink.connect<&const_nonconst_noexcept::i>(&cfunctor);
+    sink.connect<&const_nonconst_noexcept::f>(functor);
+    sink.connect<&const_nonconst_noexcept::g>(functor);
+    sink.connect<&const_nonconst_noexcept::h>(cfunctor);
+    sink.connect<&const_nonconst_noexcept::i>(cfunctor);
     sigh.publish();
 
     ASSERT_EQ(functor.cnt, 2);
     ASSERT_EQ(cfunctor.cnt, 2);
 
-    sink.disconnect<&const_nonconst_noexcept::f>(&functor);
-    sink.disconnect<&const_nonconst_noexcept::g>(&functor);
-    sink.disconnect<&const_nonconst_noexcept::h>(&cfunctor);
-    sink.disconnect<&const_nonconst_noexcept::i>(&cfunctor);
+    sink.disconnect<&const_nonconst_noexcept::f>(functor);
+    sink.disconnect<&const_nonconst_noexcept::g>(functor);
+    sink.disconnect<&const_nonconst_noexcept::h>(cfunctor);
+    sink.disconnect<&const_nonconst_noexcept::i>(cfunctor);
     sigh.publish();
 
     ASSERT_EQ(functor.cnt, 2);

+ 2 - 2
test/lib/lib.cpp

@@ -68,8 +68,8 @@ TEST(Lib, Dispatcher) {
     entt::dispatcher dispatcher;
     listener listener;
 
-    dispatcher.sink<an_event>().connect<&listener::on_an_event>(&listener);
-    dispatcher.sink<another_event>().connect<&listener::on_another_event>(&listener);
+    dispatcher.sink<an_event>().connect<&listener::on_an_event>(listener);
+    dispatcher.sink<another_event>().connect<&listener::on_another_event>(listener);
 
     listener.value = 0;