UE4之Delegate:單播

普通單播的定義

#define DECLARE_DELEGATE( DelegateName ) FUNC_DECLARE_DELEGATE( DelegateName, void )
#define FUNC_DECLARE_DELEGATE( DelegateName, ... ) \
	typedef TBaseDelegate<__VA_ARGS__> DelegateName;
class TBaseDelegate<void, ParamTypes...>: public TBaseDelegate<TTypeWrapper<void>, ParamTypes...>
{
    // ···
}

實際上是一個TBaseDelegate子類, 看父類TBaseDelegate<TTypeWrapper, ParamTypes…>的定義

template <typename WrappedRetValType, typename... ParamTypes>
class TBaseDelegate : public FDelegateBase
{
public:
    /** 定義了返回的類型. */
    typedef typename TUnwrapType<WrappedRetValType>::Type RetValType;
    // 定義一個帶有返回類型和參數的函數類型
    typedef RetValType TFuncType(ParamTypes...);
    /** 與此委託類兼容的委託實例類型的共享接口的類型定義. */
    typedef IBaseDelegateInstance<TFuncType> TDelegateInstanceInterface;

    FORCEINLINE TDelegateInstanceInterface* GetDelegateInstanceProtected() const
    {
	return (TDelegateInstanceInterface*)FDelegateBase::GetDelegateInstanceProtected();
    }
}

內部定義了一個與此委託類兼容的委託實例類型IBaseDelegateInstance,而IBaseDelegateInstance繼承自IBaseDelegateInstanceCommon

struct IBaseDelegateInstanceCommon<RetType(ArgTypes...)> : public IDelegateInstance
{
    virtual void CreateCopy(FDelegateBase& Base) = 0;
    virtual RetType Execute(ArgTypes...) const = 0;
};

IBaseDelegateInstanceCommon的模板參數RetType和ArgTyes和TBaseDelegate裏面的模板參數對應。

之後要介紹的綁定C++原生函數TBaseRawMethodDelegateInstance,綁定UObject對象成員函數TBaseUObjectMethodDelegateInstance,綁定UFunction的TBaseUFunctionDelegateInstance和綁定Lambada的TBaseFunctorDelegateInstance,都繼承自IBaseDelegateInstance

然後講一講FDelegateBase,它是單播代理類的祖先類

class FDelegateBase
{
public:
    FDelegateBase& operator=(FDelegateBase&& Other)
    {
	Unbind();
	DelegateAllocator.MoveToEmpty(Other.DelegateAllocator);
	DelegateSize = Other.DelegateSize;
	Other.DelegateSize = 0;
        return *this;
    }
    FORCEINLINE IDelegateInstance* GetDelegateInstanceProtected( ) const
    {
        return DelegateSize ? (IDelegateInstance*)DelegateAllocator.GetAllocation() : nullptr;
    }
private:
    FDelegateAllocatorType::ForElementType<FAlignedInlineDelegateType> DelegateAllocator;
    int32 DelegateSize;
};

DelegateAllocator存儲一個IDelegateInstance對象, 通過它來實現代理,獲取代理的方式就是上面代碼裏的GetDelegateInstanceProtected(),這個方法會在TBaseDelegate裏調用。

DelegateAllocator實際上是一個ForElementType類型, 繼承自ForAnyElementType,MoveToEmpty方法,以級現在的GetAllocation方法,都是定義在ForAnyElementType中的

template<typename ElementType>
class ForElementType : public ForAnyElementType
{
public:
    FORCEINLINE ElementType* GetAllocation() const
    {
        // 調用基類的GetAllocation()方法
	return (ElementType*)ForAnyElementType::GetAllocation();
    }
};
class CORE_API ForAnyElementType
{
public:
    FORCEINLINE void MoveToEmpty(ForAnyElementType& Other)
    {
	checkSlow(this != &Other);
	if (Data)
	{
		FMemory::Free(Data);
	}
	Data       = Other.Data;
	Other.Data = nullptr;
    }
    FORCEINLINE FScriptContainerElement* GetAllocation() const
    {
	return Data;
    }
private:
    FScriptContainerElement* Data;
};

然後說說具體的一些綁定過程

C++原生函數的綁定

template <typename UserClass, typename... VarTypes>
FUNCTION_CHECK_RETURN_START
inline static TBaseDelegate<RetValType, ParamTypes...> CreateRaw(UserClass* InUserObject, typename TMemFunPtrType<false, UserClass, RetValType (ParamTypes..., VarTypes...)>::Type InFunc, VarTypes... Vars)
FUNCTION_CHECK_RETURN_END
{
    TBaseDelegate<RetValType, ParamTypes...> Result;
    TBaseRawMethodDelegateInstance<false, UserClass, TFuncType, VarTypes...>::Create(Result, InUserObject, InFunc, Vars...);
    return Result;
}

上面說了,TBaseRawMethodDelegateInstance是IBaseDelegateInstance的子類,

template <bool bConst, class UserClass, typename WrappedRetValType, typename... ParamTypes, typename... VarTypes>
class TBaseRawMethodDelegateInstance<bConst, UserClass, WrappedRetValType (ParamTypes...), VarTypes...> : public IBaseDelegateInstance<typename TUnwrapType<WrappedRetValType>::Type (ParamTypes...)>
{
public:
    typedef typename TUnwrapType<WrappedRetValType>::Type RetValType;
private:
    typedef IBaseDelegateInstance<RetValType (ParamTypes...)>                                          Super;
    typedef TBaseRawMethodDelegateInstance<bConst, UserClass, RetValType (ParamTypes...), VarTypes...> UnwrappedThisType;
public:
    typedef typename TMemFunPtrType<bConst, UserClass, RetValType (ParamTypes..., VarTypes...)>::Type FMethodPtr;
	
    FORCEINLINE static void Create(FDelegateBase& Base, UserClass* InUserObject, FMethodPtr InFunc, VarTypes... Vars)
    {
	new (Base) UnwrappedThisType(InUserObject, InFunc, Vars...);
    }	
    virtual RetValType Execute(ParamTypes... Params) const override final
    {
	typedef typename TRemoveConst<UserClass>::Type MutableUserClass;
	auto MutableUserObject = const_cast<MutableUserClass*>(UserObject);
	checkSlow(MethodPtr != nullptr);
	return Payload.ApplyAfter(TMemberFunctionCaller<MutableUserClass, FMethodPtr>(MutableUserObject, MethodPtr), Params...);
    }
};

類裏面定義了返回類型別名RetValType,定義了函數指針別名FMethodPtr,這裏用到了TMemFunPtrType模板類,來看看定義

template <typename Class, typename RetType, typename... ArgTypes>
struct TMemFunPtrType<false, Class, RetType(ArgTypes...)>
{
    typedef RetType (Class::* Type)(ArgTypes...);
};

它的作用就是定義一個類成員函數指針,也指明瞭返回值類型和參數類型

然後,在Create方法裏, 在Base對象上執行TBaseRawMethodDelegateInstance的構造

FORCEINLINE static void Create(FDelegateBase& Base, UserClass* InUserObject, FMethodPtr InFunc, VarTypes... Vars)
{
    new (Base) UnwrappedThisType(InUserObject, InFunc, Vars...);
}

Create方法是在TBaseDelegate裏調用的

template <typename UserClass, typename... VarTypes>
inline void BindRaw(UserClass* InUserObject, typename TMemFunPtrType<false, UserClass, RetValType (ParamTypes..., VarTypes...)>::Type InFunc, VarTypes... Vars)
{
    *this = CreateRaw(InUserObject, InFunc, Vars...);
}

最後是執行過程Execute

Payload.ApplyAfter(TMemberFunctionCaller<MutableUserClass, FMethodPtr>(MutableUserObject, MethodPtr), Params...);

Payload是一個TTuple,可以看到,由於是ApplyAfter,因此綁定的函數在執行Execute的時候,先傳入我們在Execute的時候傳入的參數,再傳入Payload存儲的參數,兩者的參數組成實參列表,一定要和綁定的函數的參數列表一致。 Payload存儲的參數值,是在綁定的時候,位於綁定函數之後的參數包裏的Vars

TBaseRawMethodDelegateInstance<false, UserClass, TFuncType, VarTypes...>::Create(Result, InUserObject, InFunc, Vars...);

有關TTuple的,可以查看TTuple的源碼分析
它裏面用到了一個TMemberFunctionCaller,它用於執行指定類對象的成員函數,並且講函數參數包進行轉發

template <typename... ArgTypes>
auto operator()(ArgTypes&&... Args) -> decltype((Obj->*MemFunPtr)(Forward<ArgTypes>(Args)...))
{
    return (Obj->*MemFunPtr)(Forward<ArgTypes>(Args)...);
}

UE4重寫了Forward函數,它用來講參數轉發給另一個函數而不改變參數原有的左右值。Forward(Args)…進行包擴展,會將參數包裏每一個參數都進行一次Forward轉發。

UObject的綁定

UObject綁定和原生C++成員函數綁定類似, 分了const和非const函數的版本

TBaseUObjectMethodDelegateInstance也是一個IBaseDelegateInstance子類.

UFunction綁定

template <typename UObjectTemplate, typename... VarTypes>
FUNCTION_CHECK_RETURN_START
inline static TBaseDelegate<RetValType, ParamTypes...> CreateUFunction(UObjectTemplate* InUserObject, const FName& InFunctionName, VarTypes... Vars)
FUNCTION_CHECK_RETURN_END
{
    TBaseDelegate<RetValType, ParamTypes...> Result;
    TBaseUFunctionDelegateInstance<UObjectTemplate, TFuncType, VarTypes...>::Create(Result, InUserObject, InFunctionName, Vars...);
    return Result;
}

TBaseUFunctionDelegateInstance和之前的兩個略有區別, CachedFunction的查找通過反射去查找

template <class UserClass, typename WrappedRetValType, typename... ParamTypes, typename... VarTypes>
class TBaseUFunctionDelegateInstance<UserClass, WrappedRetValType (ParamTypes...), VarTypes...> : public IBaseDelegateInstance<typename TUnwrapType<WrappedRetValType>::Type (ParamTypes...)>
{
public:
    TBaseUFunctionDelegateInstance(UserClass* InUserObject, const FName& InFunctionName, VarTypes... Vars)
	: FunctionName (InFunctionName)
	, UserObjectPtr(InUserObject)
	, Payload      (Vars...)
	, Handle       (FDelegateHandle::GenerateNewHandle)
    {
	check(InFunctionName != NAME_None);
	if (InUserObject != nullptr)
	{
    	    CachedFunction = UserObjectPtr->FindFunctionChecked(InFunctionName);
	}
    }
public:
    UFunction* CachedFunction;
    FName FunctionName;
    TWeakObjectPtr<UserClass> UserObjectPtr;
    TTuple<VarTypes...> Payload;
    FDelegateHandle Handle;
};

在Execute的時候和上述的兩種方式不同

virtual RetValType Execute(ParamTypes... Params) const override final
{
    typedef TPayload<RetValType (ParamTypes..., VarTypes...)> FParmsWithPayload;
    checkSlow(IsSafeToExecute());
    TPlacementNewer<FParmsWithPayload> PayloadAndParams;
    Payload.ApplyAfter(PayloadAndParams, Params...);
    UserObjectPtr->ProcessEvent(CachedFunction, &PayloadAndParams);
    return PayloadAndParams->GetResult();
}

FParmsWithPayload構造了一個返回值爲RetValType,參數類型爲ParamTypes, 參數值爲VarTypes的Tuple. 然後調用Tuple的ApplyAfter方法。

然後在TTuple的ApplyAfter裏,會調用PayloadAndParams(),而PayloadAndParams是一個TPlacementNewer對象,它重載了函數調用符

template <typename T>
struct TPlacementNewer
{
    template <typename... ArgTypes>
    T* operator()(ArgTypes&&... Args)
    {
	check(!bConstructed);
	T* Result = new (&Bytes) T(Forward<ArgTypes>(Args)...);
	bConstructed = true;
	return Result;
    }
    T* operator->()
    {
	check(bConstructed);
	return (T*)&Bytes;
   }
private:
	TTypeCompatibleBytes<T> Bytes;
	bool                    bConstructed;
};

然後執行對象的ProcessEvent, 最後調用GetResult方法。

Lambda綁定

template <typename WrappedRetValType, typename... ParamTypes, typename FunctorType, typename... VarTypes>
class TBaseFunctorDelegateInstance<WrappedRetValType(ParamTypes...), FunctorType, VarTypes...> : public IBaseDelegateInstance<typename TUnwrapType<WrappedRetValType>::Type(ParamTypes...)>
{
public:
typedef typename TUnwrapType<WrappedRetValType>::Type RetValType;
private:
typedef IBaseDelegateInstance<typename TUnwrapType<WrappedRetValType>::Type(ParamTypes...)> Super;
typedef TBaseFunctorDelegateInstance<RetValType(ParamTypes...), FunctorType, VarTypes...>   UnwrappedThisType;
public:
    FORCEINLINE static void Create(FDelegateBase& Base, const FunctorType& InFunctor, VarTypes... Vars)
    {
	new (Base) UnwrappedThisType(InFunctor, Vars...);
    }
    virtual RetValType Execute(ParamTypes... Params) const override final
    {
	return Payload.ApplyAfter(Functor, Params...);
    }
private:
    mutable typename TRemoveConst<FunctorType>::Type Functor;
    TTuple<VarTypes...> Payload;
    FDelegateHandle Handle;
};

Lambda是一個仿函數對象,TBaseFunctorDelegateInstance類用一個FDelegateHandle來記錄代理唯一ID, 類型爲uint64

最後, Execute的時候,ApplyAfter直接調用Functor,並傳入參數Params…

virtual RetValType Execute(ParamTypes... Params) const override final
{
    return Payload.ApplyAfter(Functor, Params...);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章