@@ -475,6 +475,149 @@ class DelegateMember<TClass, RetType(Args...)> : public Delegate<RetType(Args...
475475 MemberFunc m_func = nullptr ;
476476};
477477
478+ template <class C , class R >
479+ struct DelegateMemberShared ; // Not defined
480+
481+ // / @brief `DelegateMemberShared<>` class synchronously invokes a class member target
482+ // / function using a weak pointer.
483+ // / @details This class is a "safe" version of DelegateMember. It holds a std::weak_ptr
484+ // / to the target. If the target is destroyed, the callback is silently dropped.
485+ // / @tparam TClass The class type that contains the member function.
486+ // / @tparam RetType The return type of the bound delegate function.
487+ // / @tparam Args The argument types of the bound delegate function.
488+ template <class TClass , class RetType , class ... Args>
489+ class DelegateMemberShared <TClass, RetType(Args...)> : public Delegate<RetType(Args...)> {
490+ public:
491+ typedef TClass* ObjectPtr;
492+ typedef std::shared_ptr<TClass> SharedPtr;
493+ typedef std::weak_ptr<TClass> WeakPtr;
494+ typedef RetType (TClass::* MemberFunc)(Args...);
495+ typedef RetType (TClass::* ConstMemberFunc)(Args...) const ;
496+ using ClassType = DelegateMemberShared<TClass, RetType(Args...)>;
497+
498+ // / @brief Constructor to create a class instance.
499+ // / @param[in] object The target object pointer to store.
500+ // / @param[in] func The target member function to store.
501+ DelegateMemberShared (SharedPtr object, MemberFunc func) { Bind (object, func); }
502+
503+ // / @brief Constructor to create a class instance.
504+ // / @param[in] object The target object pointer to store.
505+ // / @param[in] func The target const member function to store.
506+ DelegateMemberShared (SharedPtr object, ConstMemberFunc func) { Bind (object, func); }
507+
508+ // / @brief Copy constructor.
509+ DelegateMemberShared (const ClassType& rhs) { Assign (rhs); }
510+
511+ // / @brief Move constructor.
512+ DelegateMemberShared (ClassType&& rhs) noexcept : m_object(std::move(rhs.m_object)), m_func(rhs.m_func) { rhs.Clear (); }
513+
514+ // / @brief Default constructor.
515+ DelegateMemberShared () = default ;
516+
517+ // / @brief Destructor.
518+ ~DelegateMemberShared () { Clear (); }
519+
520+ // / @brief Bind a member function to the delegate.
521+ void Bind (SharedPtr object, MemberFunc func) {
522+ static_assert (!std::is_const<TClass>::value, " Cannot bind non-const function to const object." );
523+ m_object = object; // Implicit conversion from shared_ptr to weak_ptr
524+ m_func = func;
525+ }
526+
527+ // / @brief Bind a const member function to the delegate.
528+ void Bind (SharedPtr object, ConstMemberFunc func) {
529+ m_object = object; // Implicit conversion from shared_ptr to weak_ptr
530+ m_func = reinterpret_cast <MemberFunc>(func);
531+ }
532+
533+ // / @brief Creates a copy of the current object.
534+ virtual ClassType* Clone () const override {
535+ return new (std::nothrow) ClassType (*this );
536+ }
537+
538+ // / @brief Assigns the state of one object to another.
539+ void Assign (const ClassType& rhs) {
540+ m_object = rhs.m_object ;
541+ m_func = rhs.m_func ;
542+ }
543+
544+ // / @brief Invoke the bound delegate function synchronously.
545+ // / @details SAFELY locks the weak pointer. If object is dead, returns default.
546+ virtual RetType operator ()(Args... args) override {
547+ // 1. Try to promote weak_ptr to strong shared_ptr
548+ if (auto strongPtr = m_object.lock ())
549+ {
550+ // 2. SUCCESS: Object is alive. Invoke.
551+ if constexpr (std::is_const<TClass>::value)
552+ return std::invoke (reinterpret_cast <ConstMemberFunc>(m_func), strongPtr, std::forward<Args>(args)...);
553+ else
554+ return std::invoke (m_func, strongPtr, std::forward<Args>(args)...);
555+ }
556+
557+ // 3. FAILURE: Object is dead. Silently ignore.
558+ return RetType ();
559+ }
560+
561+ // / @brief Assignment operator.
562+ ClassType& operator =(const ClassType& rhs) {
563+ if (&rhs != this ) {
564+ Assign (rhs);
565+ }
566+ return *this ;
567+ }
568+
569+ // / @brief Move assignment operator.
570+ ClassType& operator =(ClassType&& rhs) noexcept {
571+ if (&rhs != this ) {
572+ m_object = std::move (rhs.m_object );
573+ m_func = rhs.m_func ;
574+ rhs.Clear ();
575+ }
576+ return *this ;
577+ }
578+
579+ // / @brief Clear the target function.
580+ virtual void operator =(std::nullptr_t ) noexcept {
581+ return Clear ();
582+ }
583+
584+ // / @brief Compares two delegate objects for equality.
585+ virtual bool Equal (const DelegateBase& rhs) const override {
586+ auto derivedRhs = dynamic_cast <const ClassType*>(&rhs);
587+ if (!derivedRhs) return false ;
588+
589+ // Compare Weak Pointers by locking them first
590+ auto ptr1 = m_object.lock ();
591+ auto ptr2 = derivedRhs->m_object .lock ();
592+
593+ return (ptr1 == ptr2) && (m_func == derivedRhs->m_func );
594+ }
595+
596+ // Standard operator== overloads
597+ bool operator ==(const ClassType& rhs) const noexcept { return Equal (rhs); }
598+ virtual bool operator ==(std::nullptr_t ) const noexcept override { return Empty (); }
599+ virtual bool operator !=(std::nullptr_t ) const noexcept override { return !Empty (); }
600+ friend bool operator ==(std::nullptr_t , const ClassType& rhs) noexcept { return rhs.Empty (); }
601+ friend bool operator !=(std::nullptr_t , const ClassType& rhs) noexcept { return !rhs.Empty (); }
602+
603+ // / @brief Check if the delegate is bound (Note: Doesn't check if object is alive).
604+ bool Empty () const noexcept { return m_object.expired () || !m_func; }
605+
606+ // / @brief Clear the target function.
607+ void Clear () noexcept { m_object.reset (); m_func = nullptr ; }
608+
609+ explicit operator bool () const noexcept { return !Empty (); }
610+
611+ private:
612+ bool operator <(const ClassType& rhs) const = delete ;
613+
614+ // / Weak pointer to the target object.
615+ WeakPtr m_object;
616+
617+ // / Pointer to a member function.
618+ MemberFunc m_func = nullptr ;
619+ };
620+
478621template <class R >
479622class DelegateFunction ; // Not defined
480623
@@ -721,7 +864,7 @@ auto MakeDelegate(const TClass* object, RetType(TClass::* func)(Args... args) co
721864// / @return A `DelegateMember` shared pointer bound to the specified non-const member function.
722865template <class TClass , class RetType , class ... Args>
723866auto MakeDelegate (std::shared_ptr<TClass> object, RetType(TClass::* func)(Args... args)) {
724- return DelegateMember <TClass, RetType (Args...)>(object, func);
867+ return DelegateMemberShared <TClass, RetType (Args...)>(object, func);
725868}
726869
727870// / @brief Creates a delegate that binds to a const member function with a shared pointer to the object.
@@ -733,7 +876,7 @@ auto MakeDelegate(std::shared_ptr<TClass> object, RetType(TClass::* func)(Args..
733876// / @return A `DelegateMember` shared pointer bound to the specified const member function.
734877template <class TClass , class RetType , class ... Args>
735878auto MakeDelegate (std::shared_ptr<TClass> object, RetType(TClass::* func)(Args... args) const ) {
736- return DelegateMember <TClass, RetType (Args...)>(object, func);
879+ return DelegateMemberShared <TClass, RetType (Args...)>(object, func);
737880}
738881
739882// / @brief Creates a delegate that binds to a `std::function`.
0 commit comments