diff --git a/Redcraft.Utility/Source/Private/Testing/TypeTraitsTesting.cpp b/Redcraft.Utility/Source/Private/Testing/TypeTraitsTesting.cpp index 7d4c8b8..1073c37 100644 --- a/Redcraft.Utility/Source/Private/Testing/TypeTraitsTesting.cpp +++ b/Redcraft.Utility/Source/Private/Testing/TypeTraitsTesting.cpp @@ -451,13 +451,13 @@ void TestTypeTraits() // Common.h - always_check((CSameAs::Type>)); - always_check((CSameAs::Type>)); - always_check((CSameAs::Type>)); + always_check((CSameAs>)); + always_check((CSameAs>)); + always_check((CSameAs>)); - always_check((CSameAs::Type>)); - always_check((CSameAs::Type>)); - always_check((CSameAs::Type>)); + always_check((CSameAs>)); + always_check((CSameAs>)); + always_check((CSameAs>)); always_check((CCommonType)); always_check((CCommonType)); diff --git a/Redcraft.Utility/Source/Public/Miscellaneous/Compare.h b/Redcraft.Utility/Source/Public/Miscellaneous/Compare.h index f8b6787..05b1bbb 100644 --- a/Redcraft.Utility/Source/Public/Miscellaneous/Compare.h +++ b/Redcraft.Utility/Source/Public/Miscellaneous/Compare.h @@ -10,7 +10,7 @@ NAMESPACE_REDCRAFT_BEGIN NAMESPACE_MODULE_BEGIN(Redcraft) NAMESPACE_MODULE_BEGIN(Utility) -// The result of the three-way comparison operator is the built-in type of the compiler, which is directly introduced here. +// The result of the three-way comparison operator is the built-in type of the compiler, which is directly introduced here typedef NAMESPACE_STD::partial_ordering partial_ordering; typedef NAMESPACE_STD::weak_ordering weak_ordering; @@ -44,7 +44,7 @@ template concept CThreeWayComparable = CWeaklyEqualityComparable && CPartiallyOrdered && CCommonReference&, const TRemoveReference&> && requires(const TRemoveReference& A, const TRemoveReference& B, - const TRemoveReference&, const TRemoveReference&>::Type>& C) + const TRemoveReference&, const TRemoveReference&>>& C) { { A <=> A } -> CThreeWayComparesAs; { B <=> B } -> CThreeWayComparesAs; diff --git a/Redcraft.Utility/Source/Public/Templates/Tuple.h b/Redcraft.Utility/Source/Public/Templates/Tuple.h index 1fde4b3..c40b6fe 100644 --- a/Redcraft.Utility/Source/Public/Templates/Tuple.h +++ b/Redcraft.Utility/Source/Public/Templates/Tuple.h @@ -580,6 +580,19 @@ constexpr void VisitTuple(F&& Func, FirstTupleType&& FirstTuple, TupleTypes&&... NAMESPACE_PRIVATE::TTupleVisitImpl::Value>>::F(Forward(Func), Forward(FirstTuple), Forward(Tuples)...); } +template requires requires { typename TTuple...>; } +struct TBasicCommonType, TTuple> +{ + using Type = TTuple...>; +}; + +template typename TQualifiers, template typename UQualifiers> + requires requires { typename TTuple, UQualifiers>...>; } +struct TBasicCommonReference, TTuple, TQualifiers, UQualifiers> +{ + using Type = TTuple, UQualifiers>...>; +}; + NAMESPACE_MODULE_END(Utility) NAMESPACE_MODULE_END(Redcraft) NAMESPACE_REDCRAFT_END diff --git a/Redcraft.Utility/Source/Public/Templates/TypeHash.h b/Redcraft.Utility/Source/Public/Templates/TypeHash.h index 051512a..81bf25b 100644 --- a/Redcraft.Utility/Source/Public/Templates/TypeHash.h +++ b/Redcraft.Utility/Source/Public/Templates/TypeHash.h @@ -39,8 +39,8 @@ constexpr size_t HashCombine(size_t A, size_t C) return C; } -template requires (true && ... && CConvertibleTo) -constexpr size_t HashCombine(size_t A, size_t C, Ts... InOther) +template requires (true && ... && CConvertibleTo) +constexpr size_t HashCombine(size_t A, size_t C, Types... InOther) { size_t B = HashCombine(A, C); return HashCombine(B, InOther...); diff --git a/Redcraft.Utility/Source/Public/Templates/Variant.h b/Redcraft.Utility/Source/Public/Templates/Variant.h index 9d17c6a..61e57fc 100644 --- a/Redcraft.Utility/Source/Public/Templates/Variant.h +++ b/Redcraft.Utility/Source/Public/Templates/Variant.h @@ -236,7 +236,7 @@ struct TVariant { checkf(IsValid(), TEXT("It is an error to call Visit() on an wrong TVariant. Please either check IsValid().")); - using ReturnType = typename TCommonType...>::Type; + using ReturnType = TCommonType...>; using FInvokeImpl = ReturnType(*)(F&&, void*); static constexpr FInvokeImpl InvokeImpl[] = { [](F&& Func, void* This) -> ReturnType { return InvokeResult(Forward(Func), *reinterpret_cast(This)); }... }; @@ -249,7 +249,7 @@ struct TVariant { checkf(IsValid(), TEXT("It is an error to call Visit() on an wrong TVariant. Please either check IsValid().")); - using ReturnType = typename TCommonType...>::Type; + using ReturnType = TCommonType...>; using FInvokeImpl = ReturnType(*)(F&&, void*); static constexpr FInvokeImpl InvokeImpl[] = { [](F&& Func, void* This) -> ReturnType { return InvokeResult(Forward(Func), MoveTemp(*reinterpret_cast(This))); }... }; @@ -262,7 +262,7 @@ struct TVariant { checkf(IsValid(), TEXT("It is an error to call Visit() on an wrong TVariant. Please either check IsValid().")); - using ReturnType = typename TCommonType...>::Type; + using ReturnType = TCommonType...>; using FInvokeImpl = ReturnType(*)(F&&, const void*); static constexpr FInvokeImpl InvokeImpl[] = { [](F&& Func, const void* This) -> ReturnType { return InvokeResult(Forward(Func), *reinterpret_cast(This)); }... }; @@ -275,7 +275,7 @@ struct TVariant { checkf(IsValid(), TEXT("It is an error to call Visit() on an wrong TVariant. Please either check IsValid().")); - using ReturnType = typename TCommonType...>::Type; + using ReturnType = TCommonType...>; using FInvokeImpl = ReturnType(*)(F&&, const void*); static constexpr FInvokeImpl InvokeImpl[] = { [](F&& Func, const void* This) -> ReturnType { return InvokeResult(Forward(Func), MoveTemp(*reinterpret_cast(This))); }... }; diff --git a/Redcraft.Utility/Source/Public/TypeTraits/Common.h b/Redcraft.Utility/Source/Public/TypeTraits/Common.h index ed86d7c..f7f8825 100644 --- a/Redcraft.Utility/Source/Public/TypeTraits/Common.h +++ b/Redcraft.Utility/Source/Public/TypeTraits/Common.h @@ -1,7 +1,10 @@ #pragma once #include "CoreTypes.h" +#include "Templates/Utility.h" +#include "TypeTraits/PrimaryType.h" #include "TypeTraits/Miscellaneous.h" +#include "TypeTraits/CopyQualifiers.h" #include @@ -9,31 +12,179 @@ NAMESPACE_REDCRAFT_BEGIN NAMESPACE_MODULE_BEGIN(Redcraft) NAMESPACE_MODULE_BEGIN(Utility) +// The class template is a customization point that allows users to influence the result of TCommonType for user +template struct TBasicCommonType { }; + +// The class template is a customization point that allows users to influence the result of TCommonReference for user +template typename TQualifiers, template typename UQualifiers> struct TBasicCommonReference { }; + NAMESPACE_PRIVATE_BEGIN -struct FNoopStruct { }; +// Template class declaration for the common Type implementation +template +struct TCommonTypeImpl; -template concept CCommonType = requires { typename NAMESPACE_STD::common_type_t; }; -template concept CCommonReference = requires { typename NAMESPACE_STD::common_reference_t; }; +// If sizeof...(Types) is zero, there is no member Type +template <> +struct TCommonTypeImpl<> { }; -template struct TCommonType { using Type = NAMESPACE_STD::common_type_t; }; -template struct TCommonReference { using Type = NAMESPACE_STD::common_reference_t; }; +// If sizeof...(Types) is one, the member Type names the same Type as TCommonType if it exists; otherwise there is no member Type +template +struct TCommonTypeImpl : TCommonTypeImpl { }; + +// If sizeof...(Types) is two + +// If applying TDecay to at least one of T and U produces a different Type, the member Type names the same Type as TCommonType, TDecay>, if it exists; if not, there is no member Type +template concept CDecayed = CSameAs> && CSameAs>; +template requires (!CDecayed) +struct TCommonTypeImpl : TCommonTypeImpl, TDecay> { }; + +// Otherwise, if there is a user specialization for TBasicCommonType::Type, that specialization is used +template concept CBasicCommonType = requires { typename TBasicCommonType::Type; }; +template requires (CDecayed && CBasicCommonType) +struct TCommonTypeImpl : TBasicCommonType +{ + // If such a specialization has a member named type, + // it must be a public and unambiguous member that names a cv-unqualified non-reference type to which both T and U are explicitly convertible + // Additionally, TBasicCommonType::Type and TBasicCommonType::Type must denote the same type + static_assert(CSameAs::Type, TDecay::Type>>, "The basic common type must be a cv-unqualified non-reference type"); + static_assert(CConstructibleFrom::Type, T&&> && CConstructibleFrom::Type, U&&>, "The basic common type must be a type which both T and U are explicitly convertible"); + static_assert(CSameAs::Type, typename TBasicCommonType::Type>, "TBasicCommonType::Type and TBasicCommonType::Type must denote the same type"); +}; + +// Otherwise, if TDecay() : DeclVal())> is a valid Type, the member Type denotes that Type +template concept CConditionalType = requires { typename TDecay() : DeclVal())>; }; +template requires (CDecayed && !CBasicCommonType && CConditionalType) +struct TCommonTypeImpl { using Type = TDecay() : DeclVal())>; }; + +// Otherwise, if TDecay() : DeclVal())> is a valid Type, +// where CRT and CRU are const TRemoveReference& and const TRemoveReference& respectively, the member Type denotes that Type +template concept CConditionalCRefType = requires { typename TDecay&>() : DeclVal&>())>; }; +template requires (CDecayed && !CBasicCommonType && !CConditionalType && CConditionalCRefType) +struct TCommonTypeImpl { using Type = TDecay&>() : DeclVal&>())>; }; + +// Otherwise, there is no member Type + +// If sizeof...(Types) is greater than two + +// If TCommonType exists, the member Type denotes TCommonType, R...> if such a Type exists +template requires (requires { typename TCommonTypeImpl::Type; }) +struct TCommonTypeImpl : TCommonTypeImpl::Type, W, Types...> { }; + +// In all other cases, there is no member Type +template +struct TCommonTypeImpl { }; NAMESPACE_PRIVATE_END -template struct TCommonType : TConditional, NAMESPACE_PRIVATE::TCommonType, NAMESPACE_PRIVATE::FNoopStruct> { }; -template struct TCommonReference : TConditional, NAMESPACE_PRIVATE::TCommonReference, NAMESPACE_PRIVATE::FNoopStruct> { }; +NAMESPACE_PRIVATE_BEGIN -template +// Template class declaration for the common reference implementation +template +struct TCommonReferenceImpl; + +// Template class declaration for the simple common reference Type implementation +template +struct TSimpleCommonReferenceImpl; + +// Template class declaration for the adding qualifiers implementation +template +struct TQualifiersImpl; + +// If sizeof...(T) is zero, there is no member Type +template <> +struct TCommonReferenceImpl<> { }; + +// If sizeof...(T) is one, the member Type names the same Type as T +template +struct TCommonReferenceImpl { using Type = T; }; + +// If sizeof...(Types) is two + +// If T and U are both reference types, and the simple common reference Type S of T and U exists, then the member Type Type names S +template concept CSimpleCommonReference = requires { typename TSimpleCommonReferenceImpl::Type; }; +template requires (CSimpleCommonReference) +struct TCommonReferenceImpl : TSimpleCommonReferenceImpl { }; + +// Otherwise, if TBasicCommonReference, TRemoveCVRef, TQ, UQ>::Type exists +template struct TBasicCommonReferenceImpl : TBasicCommonReference, TRemoveCVRef, TQualifiersImpl::template Apply, TQualifiersImpl::template Apply> { }; +template concept CBasicCommonReference = requires { typename TBasicCommonReferenceImpl::Type; }; +template requires (!CSimpleCommonReference && CBasicCommonReference) +struct TCommonReferenceImpl : TBasicCommonReferenceImpl +{ + // If such a specialization has a member named type, + // it must be a public and unambiguous member that names a type to which both TQualifiers and UQualifiers are convertible + // Additionally, TBasicCommonReference::Type and TBasicCommonReference::Type must denote the same type + static_assert(CConvertibleTo::Type> && CConvertibleTo::Type>, "The basic common reference must be a type to which both TQualifiers and UQualifiers are convertible"); + static_assert(CSameAs::Type, typename TBasicCommonReferenceImpl::Type>, "TBasicCommonReference::Type and TBasicCommonReference::Type must denote the same type"); +}; + +// Where TQ and UQ is a unary alias template such that TQ is U with the addition of T's cv-ref qualifiers, then the member Type Type names that Type +template struct TQualifiersImpl { template using Apply = TCopyCV; }; +template struct TQualifiersImpl { template using Apply = TAddLValueReference>; }; +template struct TQualifiersImpl { template using Apply = TAddRValueReference>; }; + +// Otherwise, if decltype(false ? Val() : Val()), where val is a function template template T Val();, is a valid Type, then the member Type Type names that Type +template T Val(); +template concept CConditionalValType = requires { typename TVoid() : Val())>; }; +template requires (!CSimpleCommonReference && !CBasicCommonReference && CConditionalValType) +struct TCommonReferenceImpl { using Type = decltype(false ? Val() : Val()); }; + +// Otherwise, if TCommonType is a valid Type, then the member Type Type names that Type +template concept CCommonTypeImpl = requires { typename TCommonTypeImpl; }; +template requires (!CSimpleCommonReference && !CBasicCommonReference && !CConditionalValType && CCommonTypeImpl) +struct TCommonReferenceImpl : TCommonTypeImpl { }; + +// Otherwise, there is no member Type. + +// If sizeof...(Types) is greater than two + +// If TCommonReference exists, the member Type denotes TCommonReference, R...> if such a Type exists +template requires (requires { typename TCommonReferenceImpl::Type; }) +struct TCommonReferenceImpl : TCommonReferenceImpl::Type, W, Types...> { }; + +// In all other cases, there is no member Type. +template +struct TCommonReferenceImpl { }; + +// If T is CV1 X & and U is CV2 Y & (i.e., both are lvalue reference types): +// their simple common reference Type is decltype(false ? DeclVal() : DeclVal()), +// where CV12 is the union of CV1 and CV2, if that Type exists and is a reference Type +template requires (CLValueReference&>() : DeclVal&>())>) +struct TSimpleCommonReferenceImpl { using Type = decltype(false ? DeclVal&>() : DeclVal&>()); }; + +// If T and U are both rvalue reference types: +// if the simple common reference Type of T & and U & exists, then let C denote that Type's corresponding rvalue reference Type +// If CConvertibleTo and CConvertibleTo are both true, then the simple common reference Type of T and U is C +template requires (CConvertibleTo::Type> &&> && CConvertibleTo::Type> &&>) +struct TSimpleCommonReferenceImpl { using Type = TRemoveReference::Type> &&; }; + +// Otherwise, one of the two types must be an lvalue reference Type A & and the other must be an rvalue reference Type B && +// Let D denote the simple common reference Type of A & and B const &, if any +// If D exists and CConvertibleTo is true, then the simple common reference Type is D +template requires (CConvertibleTo::Type>) +struct TSimpleCommonReferenceImpl { using Type = typename TSimpleCommonReferenceImpl::Type; }; +template struct TSimpleCommonReferenceImpl : TSimpleCommonReferenceImpl { }; // The order is not important + +// Otherwise, there's no simple common reference Type. +template +struct TSimpleCommonReferenceImpl { }; + +NAMESPACE_PRIVATE_END + +template using TCommonType = typename NAMESPACE_PRIVATE::TCommonTypeImpl::Type; +template using TCommonReference = typename NAMESPACE_PRIVATE::TCommonReferenceImpl::Type; + +template concept CCommonReference = - requires { typename TCommonReference::Type; } - && (true && ... && CConvertibleTo::Type>); + requires { typename TCommonReference; } + && (true && ... && CConvertibleTo>); -template +template concept CCommonType = - requires { typename TCommonType::Type; } - && (true && ... && CConstructibleFrom::Type, Ts&&>) - && CCommonReference && CCommonReference::Type&, typename TCommonReference::Type>; + requires { typename TCommonType; } + && (true && ... && CConstructibleFrom, Types&&>) + && CCommonReference && CCommonReference&, TCommonReference>; NAMESPACE_MODULE_END(Utility) NAMESPACE_MODULE_END(Redcraft) diff --git a/Redcraft.Utility/Source/Public/TypeTraits/Comparable.h b/Redcraft.Utility/Source/Public/TypeTraits/Comparable.h index a019991..bf2c60b 100644 --- a/Redcraft.Utility/Source/Public/TypeTraits/Comparable.h +++ b/Redcraft.Utility/Source/Public/TypeTraits/Comparable.h @@ -22,7 +22,7 @@ concept CWeaklyEqualityComparable = template concept CEqualityComparable = CWeaklyEqualityComparable && CWeaklyEqualityComparable && CWeaklyEqualityComparable && CCommonReference&, const TRemoveReference&> - && CWeaklyEqualityComparable&, const TRemoveReference&>::Type>; + && CWeaklyEqualityComparable&, const TRemoveReference&>>; template concept CPartiallyOrdered = @@ -43,8 +43,8 @@ concept CTotallyOrdered = CPartiallyOrdered && CPartiallyOrdered && CEqualityComparable && CEqualityComparable && CPartiallyOrdered && CEqualityComparable - && CPartiallyOrdered&, const TRemoveReference&>::Type> - && CEqualityComparable&, const TRemoveReference&>::Type>; + && CPartiallyOrdered&, const TRemoveReference&>> + && CEqualityComparable&, const TRemoveReference&>>; NAMESPACE_MODULE_END(Utility) NAMESPACE_MODULE_END(Redcraft) diff --git a/Redcraft.Utility/Source/Public/TypeTraits/Miscellaneous.h b/Redcraft.Utility/Source/Public/TypeTraits/Miscellaneous.h index 2b1f8d5..9668166 100644 --- a/Redcraft.Utility/Source/Public/TypeTraits/Miscellaneous.h +++ b/Redcraft.Utility/Source/Public/TypeTraits/Miscellaneous.h @@ -41,6 +41,13 @@ template using TRemoveCVRef = NAMESPACE_STD::remove_cvref_t template using TRemoveExtent = NAMESPACE_STD::remove_extent_t; template using TRemoveAllExtents = NAMESPACE_STD::remove_all_extents_t; +template using TAddConst = NAMESPACE_STD::add_const_t; +template using TAddVolatile = NAMESPACE_STD::add_volatile_t; +template using TAddCV = NAMESPACE_STD::add_cv_t; +template using TAddLValueReference = NAMESPACE_STD::add_lvalue_reference_t; +template using TAddRValueReference = NAMESPACE_STD::add_rvalue_reference_t; +template using TAddPointer = NAMESPACE_STD::add_pointer_t; + template using TMakeSigned = NAMESPACE_STD::make_signed_t; template using TMakeUnsigned = NAMESPACE_STD::make_unsigned_t;