diff --git a/src/entt/signal/delegate.hpp b/src/entt/signal/delegate.hpp index c7a389eca..6d3b73667 100644 --- a/src/entt/signal/delegate.hpp +++ b/src/entt/signal/delegate.hpp @@ -24,36 +24,32 @@ namespace internal { template -auto to_function_pointer(Ret(*)(Args...)) -> Ret(*)(Args...); +auto function_pointer(Ret(*)(Args...)) -> Ret(*)(Args...); -template>> -auto to_function_pointer(Ret(*)(Type &, Args...), const Payload *) -> Ret(*)(Args...); +template +auto function_pointer(Ret(*)(Type, Args...), Other &&) -> Ret(*)(Args...); -template>> -auto to_function_pointer(Ret(*)(Type *, Args...), const Payload *) -> Ret(*)(Args...); +template +auto function_pointer(Ret(Class:: *)(Args...), Other &&...) -> Ret(*)(Args...); -template -auto to_function_pointer(Ret(Class:: *)(Args...), const Class *) -> Ret(*)(Args...); +template +auto function_pointer(Ret(Class:: *)(Args...) const, Other &&...) -> Ret(*)(Args...); -template -auto to_function_pointer(Ret(Class:: *)(Args...) const, const Class *) -> Ret(*)(Args...); - - -template -auto to_function_pointer(Type Class:: *, const Class *) -> Type(*)(); +template +auto function_pointer(Type Class:: *, Other &&...) -> Type(*)(); template -using to_function_pointer_t = decltype(internal::to_function_pointer(std::declval()...)); +using function_pointer_t = decltype(internal::function_pointer(std::declval()...)); -template +template constexpr auto index_sequence_for(Ret(*)(Args...)) { - return std::index_sequence_for{}; + return std::index_sequence_for{}; } @@ -92,9 +88,8 @@ class delegate; * Unmanaged delegate for function pointers and members. Users of this class are * in charge of disconnecting instances before deleting them. * - * A delegate can be used as general purpose invoker with no memory overhead for - * free functions (with or without payload) and members provided along with an - * instance on which to invoke them. + * A delegate can be used as a general purpose invoker without memory overhead + * for free functions possibly with payloads and bound or unbound members. * * @tparam Ret Return type of a function type. * @tparam Args Types of arguments of a function type. @@ -103,14 +98,14 @@ template class delegate { using proto_fn_type = Ret(const void *, std::tuple); - template + template void connect(std::index_sequence) ENTT_NOEXCEPT { - static_assert(std::is_invocable_r_v>...>); + static_assert(std::is_invocable_r_v>...>); data = nullptr; fn = [](const void *, std::tuple args) -> Ret { // Ret(...) makes void(...) eat the return values to avoid errors - return Ret(std::invoke(Function, std::forward>>(std::get(args))...)); + return Ret(std::invoke(Candidate, std::forward>>(std::get(args))...)); }; } @@ -148,56 +143,47 @@ public: {} /** - * @brief Constructs a delegate and connects a free function to it. - * @tparam Function A valid free function pointer. + * @brief Constructs a delegate and connects a free function or an unbound + * member. + * @tparam Candidate Function or member to connect to the delegate. */ - template - delegate(connect_arg_t) ENTT_NOEXCEPT + template + delegate(connect_arg_t) ENTT_NOEXCEPT : delegate{} { - connect(); + connect(); } /** - * @brief Constructs a delegate and connects a member for a given instance - * or a free function with payload. - * @tparam Candidate Member or free function to connect to the delegate. + * @brief Constructs a delegate and connects a free function with payload or + * a bound member. + * @tparam Candidate Function or member to connect to the delegate. * @tparam Type Type of class or type of payload. * @param value_or_instance A valid reference that fits the purpose. */ template - delegate(connect_arg_t, Type &value_or_instance) ENTT_NOEXCEPT + delegate(connect_arg_t, Type &&value_or_instance) ENTT_NOEXCEPT : delegate{} { - connect(value_or_instance); + connect(std::forward(value_or_instance)); } /** - * @brief Constructs a delegate and connects a member for a given instance - * 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. + * @brief Connects a free function or an unbound member to a delegate. + * @tparam Candidate Function or member to connect to the delegate. */ - template - delegate(connect_arg_t, Type *value_or_instance) ENTT_NOEXCEPT - : delegate{} - { - connect(value_or_instance); - } - - /** - * @brief Connects a free function to a delegate. - * @tparam Function A valid free function pointer. - */ - template + template void connect() ENTT_NOEXCEPT { - connect(internal::index_sequence_for(internal::to_function_pointer_t{})); + if constexpr(std::is_member_pointer_v) { + connect(internal::index_sequence_for>>(internal::function_pointer_t{})); + } else { + connect(internal::index_sequence_for(internal::function_pointer_t{})); + } } /** - * @brief Connects a member function for a given instance or a free function - * with payload to a delegate. + * @brief Connects a free function with payload or a bound member to a + * delegate. * * The delegate isn't responsible for the connected object or the payload. * Users must always guarantee that the lifetime of the instance overcomes @@ -206,33 +192,13 @@ public: * such that the instance is the first argument before the ones used to * define the delegate itself. * - * @tparam Candidate Member or free function to connect to the delegate. + * @tparam Candidate Function or member to connect to the delegate. * @tparam Type Type of class or type of payload. * @param value_or_instance A valid reference that fits the purpose. */ template - void connect(Type &value_or_instance) ENTT_NOEXCEPT { - connect(value_or_instance, internal::index_sequence_for(internal::to_function_pointer_t{})); - } - - /** - * @brief Connects a member function for a given instance or a free function - * with payload to a delegate. - * - * The delegate isn't responsible for the connected object or the payload. - * Users must always guarantee that the lifetime of the instance overcomes - * the one of the delegate.
- * When used to connect a free function with payload, its signature must be - * such that the instance is the first argument before the ones used to - * define the delegate itself. - * - * @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. - */ - template - void connect(Type *value_or_instance) ENTT_NOEXCEPT { - connect(value_or_instance, internal::index_sequence_for(internal::to_function_pointer_t{})); + void connect(Type &&value_or_instance) ENTT_NOEXCEPT { + connect(std::forward(value_or_instance), internal::index_sequence_for(internal::function_pointer_t{})); } /** @@ -312,43 +278,21 @@ bool operator!=(const delegate &lhs, const delegate /** * @brief Deduction guide. - * - * It allows to deduce the function type of the delegate directly from a - * function provided to the constructor. - * - * @tparam Function A valid free function pointer. + * @tparam Candidate Function or member to connect to the delegate. */ -template -delegate(connect_arg_t) ENTT_NOEXCEPT --> delegate>>; +template +delegate(connect_arg_t) ENTT_NOEXCEPT +-> delegate>>; /** * @brief Deduction guide. - * - * It allows to deduce the function type of the delegate directly from a member - * or a free function with payload provided to the constructor. - * - * @tparam Candidate Member or free function to connect to the delegate. + * @tparam Candidate Function or member to connect to the delegate. * @tparam Type Type of class or type of payload. */ template -delegate(connect_arg_t, Type &) ENTT_NOEXCEPT --> delegate>>; - - -/** - * @brief Deduction guide. - * - * It allows to deduce the function type of the delegate directly from a member - * or a free function with payload provided to the constructor. - * - * @tparam Candidate Member or free function to connect to the delegate. - * @tparam Type Type of class or type of payload. - */ -template -delegate(connect_arg_t, Type *) ENTT_NOEXCEPT --> delegate>>; +delegate(connect_arg_t, Type &&) ENTT_NOEXCEPT +-> delegate>>; } diff --git a/test/entt/signal/delegate.cpp b/test/entt/signal/delegate.cpp index 4feed99ae..ec92acdeb 100644 --- a/test/entt/signal/delegate.cpp +++ b/test/entt/signal/delegate.cpp @@ -352,3 +352,19 @@ TEST(Delegate, TheLessTheBetter) { ASSERT_EQ(delegate(3, 'c'), 6); } + +TEST(Delegate, UnboundDataMember) { + entt::delegate delegate; + delegate.connect<&delegate_functor::data_member>(); + delegate_functor functor; + + ASSERT_EQ(delegate(functor), 42); +} + +TEST(Delegate, UnboundMemberFunction) { + entt::delegate delegate; + delegate.connect<&delegate_functor::operator()>(); + delegate_functor functor; + + ASSERT_EQ(delegate(&functor, 3), 6); +}