diff --git a/Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp b/Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp index 8c4b190..ebb6a67 100644 --- a/Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp +++ b/Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp @@ -1069,11 +1069,11 @@ void TestFunction() // TFunction ObjectE = MoveTemp(RefA); // TUniqueFunction UniqueE = MoveTemp(RefA); - TFunctionRef RefF = MoveTemp(ObjectA); +// TFunctionRef RefF = MoveTemp(ObjectA); TFunction ObjectF = MoveTemp(ObjectA); TUniqueFunction UniqueF = MoveTemp(ObjectA); - TFunctionRef RefG = MoveTemp(UniqueA); +// TFunctionRef RefG = MoveTemp(UniqueA); // TFunction ObjectG = MoveTemp(UniqueA); TUniqueFunction UniqueG = MoveTemp(UniqueA); } diff --git a/Redcraft.Utility/Source/Public/Templates/Function.h b/Redcraft.Utility/Source/Public/Templates/Function.h index 3f9ce9e..0d4562a 100644 --- a/Redcraft.Utility/Source/Public/Templates/Function.h +++ b/Redcraft.Utility/Source/Public/Templates/Function.h @@ -94,13 +94,21 @@ struct TIsInvocableResultWithSpecifiers struct TIsInvocableResultWithSpecifiers : TIsInvocableResult { }; -template struct TFunctionCallSpecifiers; -template struct TFunctionCallSpecifiers { using Type = T& ; }; -template struct TFunctionCallSpecifiers { using Type = T& ; }; -template struct TFunctionCallSpecifiers { using Type = T&&; }; -template struct TFunctionCallSpecifiers { using Type = const T& ; }; -template struct TFunctionCallSpecifiers { using Type = const T& ; }; -template struct TFunctionCallSpecifiers { using Type = const T&&; }; +template struct TFunctionCallConst; +template struct TFunctionCallConst { using Type = T; }; +template struct TFunctionCallConst { using Type = T; }; +template struct TFunctionCallConst { using Type = T; }; +template struct TFunctionCallConst { using Type = const T; }; +template struct TFunctionCallConst { using Type = const T; }; +template struct TFunctionCallConst { using Type = const T; }; + +template struct TFunctionCallConstRef; +template struct TFunctionCallConstRef { using Type = T& ; }; +template struct TFunctionCallConstRef { using Type = T& ; }; +template struct TFunctionCallConstRef { using Type = T&&; }; +template struct TFunctionCallConstRef { using Type = const T& ; }; +template struct TFunctionCallConstRef { using Type = const T& ; }; +template struct TFunctionCallConstRef { using Type = const T&&; }; template struct alignas(InlineAlignment) TFunctionImpl @@ -128,7 +136,7 @@ public: || FunctionType == EFunctionType::Reference) FORCEINLINE TFunctionImpl(T&& InValue) { - using DecayedFunctorType = typename TDecay::Type; + using DecayedType = typename TDecay::Type; if constexpr (FunctionType == EFunctionType::Reference) { @@ -136,7 +144,7 @@ public: } if (!FFunctionIsBound::F(InValue)) Callable = nullptr; - else EmplaceImpl(Forward(InValue)); + else EmplaceImpl(Forward(InValue)); } template requires (FunctionType != EFunctionType::Reference) @@ -145,18 +153,28 @@ public: || (FunctionType == EFunctionType::Unique && TIsMoveConstructible::Type>::Value)) FORCEINLINE TFunctionImpl(TInPlaceType, ArgTypes&&... Args) { - using DecayedFunctorType = typename TDecay::Type; - EmplaceImpl(Forward(Args)...); + using DecayedType = typename TDecay::Type; + EmplaceImpl(Forward(Args)...); } + // Construct TFunctionRef from TFunction or TFunctionUnique template - requires (FunctionType == EFunctionType::Reference) && (OtherFunctionType != EFunctionType::Reference) + requires (FunctionType == EFunctionType::Reference) && (OtherFunctionType != EFunctionType::Reference) && (TIsSame::Type, void>::Value) + FORCEINLINE TFunctionImpl(TFunctionImpl& InValue) + { + checkf(FFunctionIsBound::F(InValue), TEXT("Cannot bind a null/unbound callable to a TFunctionRef")); + EmplaceImpl>(InValue); + } + + // Construct TFunctionRef from TFunction or TFunctionUnique + template + requires (FunctionType == EFunctionType::Reference) && (OtherFunctionType != EFunctionType::Reference) && (TIsSame::Type, const void>::Value) FORCEINLINE TFunctionImpl(const TFunctionImpl& InValue) { checkf(FFunctionIsBound::F(InValue), TEXT("Cannot bind a null/unbound callable to a TFunctionRef")); EmplaceImpl>(InValue); } - + FORCEINLINE TFunctionImpl(const TFunctionImpl& InValue) requires (FunctionType == EFunctionType::Unique) : Callable((*reinterpret_cast(&InValue)).Callable), Storage((*reinterpret_cast(&InValue)).Storage) { } @@ -201,10 +219,10 @@ public: || (FunctionType == EFunctionType::Unique && TIsMoveConstructible::Type>::Value)) FORCEINLINE TFunctionImpl& operator=(T&& InValue) { - using DecayedFunctorType = typename TDecay::Type; + using DecayedType = typename TDecay::Type; if (!FFunctionIsBound::F(InValue)) Reset(); - else EmplaceImpl(Forward(InValue)); + else EmplaceImpl(Forward(InValue)); return *this; } @@ -216,9 +234,9 @@ public: || (FunctionType == EFunctionType::Unique && TIsMoveConstructible::Type>::Value)) FORCEINLINE typename TDecay::Type& Emplace(ArgTypes&&... Args) { - using DecayedFunctorType = typename TDecay::Type; - EmplaceImpl(Forward(Args)...); - return Target(); + using DecayedType = typename TDecay::Type; + EmplaceImpl(Forward(Args)...); + return Target(); } FORCEINLINE ResultType operator()(Types... Args) requires (Specifiers == EFunctionSpecifiers::None ) { return CallImpl(Forward(Args)...); } @@ -264,28 +282,31 @@ public: private: - using StorageType = typename TConditional>::Type; - using StorageRef = typename TConditional::Type&>::Type; + using StorageType = typename TConditional::Type*, TAny>::Type; + using StorageRef = typename TConditional::Type*, typename TFunctionCallConstRef::Type&>::Type; + using CallFunc = ResultType(*)(StorageRef, Types&&...); StorageType Storage; CallFunc Callable; - template + template FORCEINLINE void EmplaceImpl(ArgTypes&&... Args) { - if constexpr (FunctionType == EFunctionType::Reference) Storage = ((void*)&Args, ...); - else Storage.template Emplace(Forward(Args)...); + using CallableType = typename TFunctionCallConst::Type; + + if constexpr (FunctionType == EFunctionType::Reference) Storage = ((reinterpret_cast(&Args)), ...); + else Storage.template Emplace(Forward(Args)...); Callable = [](StorageRef Storage, Types&&... Args) -> ResultType { const auto GetFunc = [&Storage]() -> decltype(auto) { - if constexpr (FunctionType == EFunctionType::Reference) return *reinterpret_cast(Storage); - else return Storage.template GetValue(); + if constexpr (FunctionType == EFunctionType::Reference) return *reinterpret_cast(Storage); + else return Storage.template GetValue(); }; - return InvokeResult(Forward::Type>(GetFunc()), Forward(Args)...); + return InvokeResult(Forward::Type>(GetFunc()), Forward(Args)...); }; }