refactor(templates): disable TFunctionRef to bind r-valued callable

This commit is contained in:
_Redstone_c_ 2022-05-01 18:02:26 +08:00
parent eb814e37d3
commit a737eea487
2 changed files with 49 additions and 28 deletions

View File

@ -1069,11 +1069,11 @@ void TestFunction()
// TFunction<void()> ObjectE = MoveTemp(RefA); // TFunction<void()> ObjectE = MoveTemp(RefA);
// TUniqueFunction<void()> UniqueE = MoveTemp(RefA); // TUniqueFunction<void()> UniqueE = MoveTemp(RefA);
TFunctionRef<void()> RefF = MoveTemp(ObjectA); // TFunctionRef<void()> RefF = MoveTemp(ObjectA);
TFunction<void()> ObjectF = MoveTemp(ObjectA); TFunction<void()> ObjectF = MoveTemp(ObjectA);
TUniqueFunction<void()> UniqueF = MoveTemp(ObjectA); TUniqueFunction<void()> UniqueF = MoveTemp(ObjectA);
TFunctionRef<void()> RefG = MoveTemp(UniqueA); // TFunctionRef<void()> RefG = MoveTemp(UniqueA);
// TFunction<void()> ObjectG = MoveTemp(UniqueA); // TFunction<void()> ObjectG = MoveTemp(UniqueA);
TUniqueFunction<void()> UniqueG = MoveTemp(UniqueA); TUniqueFunction<void()> UniqueG = MoveTemp(UniqueA);
} }

View File

@ -94,13 +94,21 @@ struct TIsInvocableResultWithSpecifiers<EFunctionSpecifiers::ConstLValue, R, F,
template <typename R, typename F, typename... Types> template <typename R, typename F, typename... Types>
struct TIsInvocableResultWithSpecifiers<EFunctionSpecifiers::ConstRValue, R, F, Types...> : TIsInvocableResult<R, const F, Types...> { }; struct TIsInvocableResultWithSpecifiers<EFunctionSpecifiers::ConstRValue, R, F, Types...> : TIsInvocableResult<R, const F, Types...> { };
template <typename T, EFunctionSpecifiers Specifiers> struct TFunctionCallSpecifiers; template <typename T, EFunctionSpecifiers Specifiers> struct TFunctionCallConst;
template <typename T> struct TFunctionCallSpecifiers<T, EFunctionSpecifiers::None> { using Type = T& ; }; template <typename T> struct TFunctionCallConst<T, EFunctionSpecifiers::None> { using Type = T; };
template <typename T> struct TFunctionCallSpecifiers<T, EFunctionSpecifiers::LValue> { using Type = T& ; }; template <typename T> struct TFunctionCallConst<T, EFunctionSpecifiers::LValue> { using Type = T; };
template <typename T> struct TFunctionCallSpecifiers<T, EFunctionSpecifiers::RValue> { using Type = T&&; }; template <typename T> struct TFunctionCallConst<T, EFunctionSpecifiers::RValue> { using Type = T; };
template <typename T> struct TFunctionCallSpecifiers<T, EFunctionSpecifiers::Const> { using Type = const T& ; }; template <typename T> struct TFunctionCallConst<T, EFunctionSpecifiers::Const> { using Type = const T; };
template <typename T> struct TFunctionCallSpecifiers<T, EFunctionSpecifiers::ConstLValue> { using Type = const T& ; }; template <typename T> struct TFunctionCallConst<T, EFunctionSpecifiers::ConstLValue> { using Type = const T; };
template <typename T> struct TFunctionCallSpecifiers<T, EFunctionSpecifiers::ConstRValue> { using Type = const T&&; }; template <typename T> struct TFunctionCallConst<T, EFunctionSpecifiers::ConstRValue> { using Type = const T; };
template <typename T, EFunctionSpecifiers Specifiers> struct TFunctionCallConstRef;
template <typename T> struct TFunctionCallConstRef<T, EFunctionSpecifiers::None> { using Type = T& ; };
template <typename T> struct TFunctionCallConstRef<T, EFunctionSpecifiers::LValue> { using Type = T& ; };
template <typename T> struct TFunctionCallConstRef<T, EFunctionSpecifiers::RValue> { using Type = T&&; };
template <typename T> struct TFunctionCallConstRef<T, EFunctionSpecifiers::Const> { using Type = const T& ; };
template <typename T> struct TFunctionCallConstRef<T, EFunctionSpecifiers::ConstLValue> { using Type = const T& ; };
template <typename T> struct TFunctionCallConstRef<T, EFunctionSpecifiers::ConstRValue> { using Type = const T&&; };
template <typename R, typename... Types, size_t InlineSize, size_t InlineAlignment, EFunctionSpecifiers Specifiers, EFunctionType FunctionType> template <typename R, typename... Types, size_t InlineSize, size_t InlineAlignment, EFunctionSpecifiers Specifiers, EFunctionType FunctionType>
struct alignas(InlineAlignment) TFunctionImpl<R(Types...), InlineSize, InlineAlignment, Specifiers, FunctionType> struct alignas(InlineAlignment) TFunctionImpl<R(Types...), InlineSize, InlineAlignment, Specifiers, FunctionType>
@ -128,7 +136,7 @@ public:
|| FunctionType == EFunctionType::Reference) || FunctionType == EFunctionType::Reference)
FORCEINLINE TFunctionImpl(T&& InValue) FORCEINLINE TFunctionImpl(T&& InValue)
{ {
using DecayedFunctorType = typename TDecay<T>::Type; using DecayedType = typename TDecay<T>::Type;
if constexpr (FunctionType == EFunctionType::Reference) if constexpr (FunctionType == EFunctionType::Reference)
{ {
@ -136,7 +144,7 @@ public:
} }
if (!FFunctionIsBound::F(InValue)) Callable = nullptr; if (!FFunctionIsBound::F(InValue)) Callable = nullptr;
else EmplaceImpl<DecayedFunctorType>(Forward<T>(InValue)); else EmplaceImpl<DecayedType>(Forward<T>(InValue));
} }
template <typename T, typename... ArgTypes> requires (FunctionType != EFunctionType::Reference) template <typename T, typename... ArgTypes> requires (FunctionType != EFunctionType::Reference)
@ -145,18 +153,28 @@ public:
|| (FunctionType == EFunctionType::Unique && TIsMoveConstructible<typename TDecay<T>::Type>::Value)) || (FunctionType == EFunctionType::Unique && TIsMoveConstructible<typename TDecay<T>::Type>::Value))
FORCEINLINE TFunctionImpl(TInPlaceType<T>, ArgTypes&&... Args) FORCEINLINE TFunctionImpl(TInPlaceType<T>, ArgTypes&&... Args)
{ {
using DecayedFunctorType = typename TDecay<T>::Type; using DecayedType = typename TDecay<T>::Type;
EmplaceImpl<DecayedFunctorType>(Forward<ArgTypes>(Args)...); EmplaceImpl<DecayedType>(Forward<ArgTypes>(Args)...);
} }
// Construct TFunctionRef from TFunction or TFunctionUnique
template <size_t OtherInlineSize, size_t OtherInlineAlignment, EFunctionType OtherFunctionType> template <size_t OtherInlineSize, size_t OtherInlineAlignment, EFunctionType OtherFunctionType>
requires (FunctionType == EFunctionType::Reference) && (OtherFunctionType != EFunctionType::Reference) requires (FunctionType == EFunctionType::Reference) && (OtherFunctionType != EFunctionType::Reference) && (TIsSame<typename TFunctionCallConst<void, Specifiers>::Type, void>::Value)
FORCEINLINE TFunctionImpl(TFunctionImpl<R(Types...), OtherInlineSize, OtherInlineAlignment, Specifiers, OtherFunctionType>& InValue)
{
checkf(FFunctionIsBound::F(InValue), TEXT("Cannot bind a null/unbound callable to a TFunctionRef"));
EmplaceImpl<TFunctionImpl<R(Types...), OtherInlineSize, OtherInlineAlignment, Specifiers, OtherFunctionType>>(InValue);
}
// Construct TFunctionRef from TFunction or TFunctionUnique
template <size_t OtherInlineSize, size_t OtherInlineAlignment, EFunctionType OtherFunctionType>
requires (FunctionType == EFunctionType::Reference) && (OtherFunctionType != EFunctionType::Reference) && (TIsSame<typename TFunctionCallConst<void, Specifiers>::Type, const void>::Value)
FORCEINLINE TFunctionImpl(const TFunctionImpl<R(Types...), OtherInlineSize, OtherInlineAlignment, Specifiers, OtherFunctionType>& InValue) FORCEINLINE TFunctionImpl(const TFunctionImpl<R(Types...), OtherInlineSize, OtherInlineAlignment, Specifiers, OtherFunctionType>& InValue)
{ {
checkf(FFunctionIsBound::F(InValue), TEXT("Cannot bind a null/unbound callable to a TFunctionRef")); checkf(FFunctionIsBound::F(InValue), TEXT("Cannot bind a null/unbound callable to a TFunctionRef"));
EmplaceImpl<TFunctionImpl<R(Types...), OtherInlineSize, OtherInlineAlignment, Specifiers, OtherFunctionType>>(InValue); EmplaceImpl<TFunctionImpl<R(Types...), OtherInlineSize, OtherInlineAlignment, Specifiers, OtherFunctionType>>(InValue);
} }
FORCEINLINE TFunctionImpl(const TFunctionImpl<R(Types...), InlineSize, InlineAlignment, Specifiers, EFunctionType::Object>& InValue) requires (FunctionType == EFunctionType::Unique) FORCEINLINE TFunctionImpl(const TFunctionImpl<R(Types...), InlineSize, InlineAlignment, Specifiers, EFunctionType::Object>& InValue) requires (FunctionType == EFunctionType::Unique)
: Callable((*reinterpret_cast<const TFunctionImpl*>(&InValue)).Callable), Storage((*reinterpret_cast<const TFunctionImpl*>(&InValue)).Storage) : Callable((*reinterpret_cast<const TFunctionImpl*>(&InValue)).Callable), Storage((*reinterpret_cast<const TFunctionImpl*>(&InValue)).Storage)
{ } { }
@ -201,10 +219,10 @@ public:
|| (FunctionType == EFunctionType::Unique && TIsMoveConstructible<typename TDecay<T>::Type>::Value)) || (FunctionType == EFunctionType::Unique && TIsMoveConstructible<typename TDecay<T>::Type>::Value))
FORCEINLINE TFunctionImpl& operator=(T&& InValue) FORCEINLINE TFunctionImpl& operator=(T&& InValue)
{ {
using DecayedFunctorType = typename TDecay<T>::Type; using DecayedType = typename TDecay<T>::Type;
if (!FFunctionIsBound::F(InValue)) Reset(); if (!FFunctionIsBound::F(InValue)) Reset();
else EmplaceImpl<DecayedFunctorType>(Forward<T>(InValue)); else EmplaceImpl<DecayedType>(Forward<T>(InValue));
return *this; return *this;
} }
@ -216,9 +234,9 @@ public:
|| (FunctionType == EFunctionType::Unique && TIsMoveConstructible<typename TDecay<T>::Type>::Value)) || (FunctionType == EFunctionType::Unique && TIsMoveConstructible<typename TDecay<T>::Type>::Value))
FORCEINLINE typename TDecay<T>::Type& Emplace(ArgTypes&&... Args) FORCEINLINE typename TDecay<T>::Type& Emplace(ArgTypes&&... Args)
{ {
using DecayedFunctorType = typename TDecay<T>::Type; using DecayedType = typename TDecay<T>::Type;
EmplaceImpl<DecayedFunctorType>(Forward<ArgTypes>(Args)...); EmplaceImpl<DecayedType>(Forward<ArgTypes>(Args)...);
return Target<DecayedFunctorType>(); return Target<DecayedType>();
} }
FORCEINLINE ResultType operator()(Types... Args) requires (Specifiers == EFunctionSpecifiers::None ) { return CallImpl(Forward<Types>(Args)...); } FORCEINLINE ResultType operator()(Types... Args) requires (Specifiers == EFunctionSpecifiers::None ) { return CallImpl(Forward<Types>(Args)...); }
@ -264,28 +282,31 @@ public:
private: private:
using StorageType = typename TConditional<FunctionType == EFunctionType::Reference, void*, TAny<InlineSize, 1>>::Type; using StorageType = typename TConditional<FunctionType == EFunctionType::Reference, typename TFunctionCallConst<void, Specifiers>::Type*, TAny<InlineSize, 1>>::Type;
using StorageRef = typename TConditional<FunctionType == EFunctionType::Reference, void*, typename TFunctionCallSpecifiers<StorageType, Specifiers>::Type&>::Type; using StorageRef = typename TConditional<FunctionType == EFunctionType::Reference, typename TFunctionCallConst<void, Specifiers>::Type*, typename TFunctionCallConstRef<StorageType, Specifiers>::Type&>::Type;
using CallFunc = ResultType(*)(StorageRef, Types&&...); using CallFunc = ResultType(*)(StorageRef, Types&&...);
StorageType Storage; StorageType Storage;
CallFunc Callable; CallFunc Callable;
template <typename SelectedType, typename... ArgTypes> template <typename DecayedType, typename... ArgTypes>
FORCEINLINE void EmplaceImpl(ArgTypes&&... Args) FORCEINLINE void EmplaceImpl(ArgTypes&&... Args)
{ {
if constexpr (FunctionType == EFunctionType::Reference) Storage = ((void*)&Args, ...); using CallableType = typename TFunctionCallConst<DecayedType, Specifiers>::Type;
else Storage.template Emplace<SelectedType>(Forward<ArgTypes>(Args)...);
if constexpr (FunctionType == EFunctionType::Reference) Storage = ((reinterpret_cast<StorageType>(&Args)), ...);
else Storage.template Emplace<DecayedType>(Forward<ArgTypes>(Args)...);
Callable = [](StorageRef Storage, Types&&... Args) -> ResultType Callable = [](StorageRef Storage, Types&&... Args) -> ResultType
{ {
const auto GetFunc = [&Storage]() -> decltype(auto) const auto GetFunc = [&Storage]() -> decltype(auto)
{ {
if constexpr (FunctionType == EFunctionType::Reference) return *reinterpret_cast<SelectedType*>(Storage); if constexpr (FunctionType == EFunctionType::Reference) return *reinterpret_cast<CallableType*>(Storage);
else return Storage.template GetValue<SelectedType>(); else return Storage.template GetValue<DecayedType>();
}; };
return InvokeResult<R>(Forward<typename TFunctionCallSpecifiers<SelectedType, Specifiers>::Type>(GetFunc()), Forward<Types>(Args)...); return InvokeResult<R>(Forward<typename TFunctionCallConstRef<CallableType, Specifiers>::Type>(GetFunc()), Forward<Types>(Args)...);
}; };
} }