refactor(typetraits): replaces template class type traits with alias template for TypeTraits/Common.h

This commit is contained in:
_Redstone_c_ 2022-05-29 23:18:20 +08:00
parent c6620da1dd
commit 8b902d15a4
8 changed files with 202 additions and 31 deletions

View File

@ -451,13 +451,13 @@ void TestTypeTraits()
// Common.h
always_check((CSameAs<int32, TCommonType<int8, int32>::Type>));
always_check((CSameAs<int64, TCommonType<int8, int32, int64>::Type>));
always_check((CSameAs<double, TCommonType<float, double>::Type>));
always_check((CSameAs<int32, TCommonType<int8, int32>>));
always_check((CSameAs<int64, TCommonType<int8, int32, int64>>));
always_check((CSameAs<double, TCommonType<float, double>>));
always_check((CSameAs<int32, TCommonReference<int8, int32>::Type>));
always_check((CSameAs<int64, TCommonReference<int8, int32, int64>::Type>));
always_check((CSameAs<double, TCommonReference<float, double>::Type>));
always_check((CSameAs<int32, TCommonReference<int8, int32>>));
always_check((CSameAs<int64, TCommonReference<int8, int32, int64>>));
always_check((CSameAs<double, TCommonReference<float, double>>));
always_check((CCommonType<int32, int32>));
always_check((CCommonType<int8, int32>));

View File

@ -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 <typename T, typename U = T, typename OrderingType = partial_ordering>
concept CThreeWayComparable = CWeaklyEqualityComparable<T, U> && CPartiallyOrdered<T, U>
&& CCommonReference<const TRemoveReference<T>&, const TRemoveReference<U>&>
&& requires(const TRemoveReference<T>& A, const TRemoveReference<U>& B,
const TRemoveReference<typename TCommonReference<const TRemoveReference<T>&, const TRemoveReference<U>&>::Type>& C)
const TRemoveReference<TCommonReference<const TRemoveReference<T>&, const TRemoveReference<U>&>>& C)
{
{ A <=> A } -> CThreeWayComparesAs<OrderingType>;
{ B <=> B } -> CThreeWayComparesAs<OrderingType>;

View File

@ -580,6 +580,19 @@ constexpr void VisitTuple(F&& Func, FirstTupleType&& FirstTuple, TupleTypes&&...
NAMESPACE_PRIVATE::TTupleVisitImpl<TMakeIndexSequence<TTupleElementSize<FirstTupleType>::Value>>::F(Forward<F>(Func), Forward<FirstTupleType>(FirstTuple), Forward<TupleTypes>(Tuples)...);
}
template <typename... Ts, typename... Us> requires requires { typename TTuple<TCommonType<Ts, Us>...>; }
struct TBasicCommonType<TTuple<Ts...>, TTuple<Us...>>
{
using Type = TTuple<TCommonType<Ts, Us>...>;
};
template <typename... Ts, typename... Us, template<typename> typename TQualifiers, template<typename> typename UQualifiers>
requires requires { typename TTuple<TCommonReference<TQualifiers<Ts>, UQualifiers<Us>>...>; }
struct TBasicCommonReference<TTuple<Ts...>, TTuple<Us...>, TQualifiers, UQualifiers>
{
using Type = TTuple<TCommonReference<TQualifiers<Ts>, UQualifiers<Us>>...>;
};
NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft)
NAMESPACE_REDCRAFT_END

View File

@ -39,8 +39,8 @@ constexpr size_t HashCombine(size_t A, size_t C)
return C;
}
template <typename... Ts> requires (true && ... && CConvertibleTo<Ts, size_t>)
constexpr size_t HashCombine(size_t A, size_t C, Ts... InOther)
template <typename... Types> requires (true && ... && CConvertibleTo<Types, size_t>)
constexpr size_t HashCombine(size_t A, size_t C, Types... InOther)
{
size_t B = HashCombine(A, C);
return HashCombine(B, InOther...);

View File

@ -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<TInvokeResult<F, Types>...>::Type;
using ReturnType = TCommonType<TInvokeResult<F, Types>...>;
using FInvokeImpl = ReturnType(*)(F&&, void*);
static constexpr FInvokeImpl InvokeImpl[] = { [](F&& Func, void* This) -> ReturnType { return InvokeResult<ReturnType>(Forward<F>(Func), *reinterpret_cast<Types*>(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<TInvokeResult<F, Types>...>::Type;
using ReturnType = TCommonType<TInvokeResult<F, Types>...>;
using FInvokeImpl = ReturnType(*)(F&&, void*);
static constexpr FInvokeImpl InvokeImpl[] = { [](F&& Func, void* This) -> ReturnType { return InvokeResult<ReturnType>(Forward<F>(Func), MoveTemp(*reinterpret_cast<Types*>(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<TInvokeResult<F, Types>...>::Type;
using ReturnType = TCommonType<TInvokeResult<F, Types>...>;
using FInvokeImpl = ReturnType(*)(F&&, const void*);
static constexpr FInvokeImpl InvokeImpl[] = { [](F&& Func, const void* This) -> ReturnType { return InvokeResult<ReturnType>(Forward<F>(Func), *reinterpret_cast<const Types*>(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<TInvokeResult<F, Types>...>::Type;
using ReturnType = TCommonType<TInvokeResult<F, Types>...>;
using FInvokeImpl = ReturnType(*)(F&&, const void*);
static constexpr FInvokeImpl InvokeImpl[] = { [](F&& Func, const void* This) -> ReturnType { return InvokeResult<ReturnType>(Forward<F>(Func), MoveTemp(*reinterpret_cast<const Types*>(This))); }... };

View File

@ -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 <type_traits>
@ -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 <typename T, typename U> struct TBasicCommonType { };
// The class template is a customization point that allows users to influence the result of TCommonReference for user
template <typename T, typename U, template<typename> typename TQualifiers, template<typename> typename UQualifiers> struct TBasicCommonReference { };
NAMESPACE_PRIVATE_BEGIN
struct FNoopStruct { };
// Template class declaration for the common Type implementation
template <typename...>
struct TCommonTypeImpl;
template <typename... Types> concept CCommonType = requires { typename NAMESPACE_STD::common_type_t<Types...>; };
template <typename... Types> concept CCommonReference = requires { typename NAMESPACE_STD::common_reference_t<Types...>; };
// If sizeof...(Types) is zero, there is no member Type
template <>
struct TCommonTypeImpl<> { };
template <typename... Types> struct TCommonType { using Type = NAMESPACE_STD::common_type_t<Types...>; };
template <typename... Types> struct TCommonReference { using Type = NAMESPACE_STD::common_reference_t<Types...>; };
// If sizeof...(Types) is one, the member Type names the same Type as TCommonType<T, T> if it exists; otherwise there is no member Type
template <typename T>
struct TCommonTypeImpl<T> : TCommonTypeImpl<T, T> { };
// 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<T>, TDecay<U>>, if it exists; if not, there is no member Type
template <typename T, typename U> concept CDecayed = CSameAs<T, TDecay<T>> && CSameAs<U, TDecay<U>>;
template <typename T, typename U> requires (!CDecayed<T, U>)
struct TCommonTypeImpl<T, U> : TCommonTypeImpl<TDecay<T>, TDecay<U>> { };
// Otherwise, if there is a user specialization for TBasicCommonType<T, U>::Type, that specialization is used
template <typename T, typename U> concept CBasicCommonType = requires { typename TBasicCommonType<T, U>::Type; };
template <typename T, typename U> requires (CDecayed<T, U> && CBasicCommonType<T, U>)
struct TCommonTypeImpl<T, U> : TBasicCommonType<T, U>
{
// 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<T, U>::Type and TBasicCommonType<U, T>::Type must denote the same type
static_assert(CSameAs<typename TBasicCommonType<T, U>::Type, TDecay<typename TBasicCommonType<T, U>::Type>>, "The basic common type must be a cv-unqualified non-reference type");
static_assert(CConstructibleFrom<typename TBasicCommonType<T, U>::Type, T&&> && CConstructibleFrom<typename TBasicCommonType<T, U>::Type, U&&>, "The basic common type must be a type which both T and U are explicitly convertible");
static_assert(CSameAs<typename TBasicCommonType<T, U>::Type, typename TBasicCommonType<U, T>::Type>, "TBasicCommonType<T, U>::Type and TBasicCommonType<U, T>::Type must denote the same type");
};
// Otherwise, if TDecay<decltype(false ? DeclVal<T>() : DeclVal<U>())> is a valid Type, the member Type denotes that Type
template <typename T, typename U> concept CConditionalType = requires { typename TDecay<decltype(false ? DeclVal<T>() : DeclVal<U>())>; };
template <typename T, typename U> requires (CDecayed<T, U> && !CBasicCommonType<T, U> && CConditionalType<T, U>)
struct TCommonTypeImpl<T, U> { using Type = TDecay<decltype(false ? DeclVal<T>() : DeclVal<U>())>; };
// Otherwise, if TDecay<decltype(false ? DeclVal<CRT>() : DeclVal<CRU>())> is a valid Type,
// where CRT and CRU are const TRemoveReference<T>& and const TRemoveReference<U>& respectively, the member Type denotes that Type
template <typename T, typename U> concept CConditionalCRefType = requires { typename TDecay<decltype(false ? DeclVal<const TRemoveReference<T>&>() : DeclVal<const TRemoveReference<U>&>())>; };
template <typename T, typename U> requires (CDecayed<T, U> && !CBasicCommonType<T, U> && !CConditionalType<T, U> && CConditionalCRefType<T, U>)
struct TCommonTypeImpl<T, U> { using Type = TDecay<decltype(false ? DeclVal<const TRemoveReference<T>&>() : DeclVal<const TRemoveReference<U>&>())>; };
// Otherwise, there is no member Type
// If sizeof...(Types) is greater than two
// If TCommonType<T, U> exists, the member Type denotes TCommonType<TCommonType<T, U>, R...> if such a Type exists
template <typename T, typename U, typename W, typename... Types> requires (requires { typename TCommonTypeImpl<T, U>::Type; })
struct TCommonTypeImpl<T, U, W, Types...> : TCommonTypeImpl<typename TCommonTypeImpl<T, U>::Type, W, Types...> { };
// In all other cases, there is no member Type
template <typename...>
struct TCommonTypeImpl { };
NAMESPACE_PRIVATE_END
template <typename... Types> struct TCommonType : TConditional<NAMESPACE_PRIVATE::CCommonType<Types...>, NAMESPACE_PRIVATE::TCommonType<Types...>, NAMESPACE_PRIVATE::FNoopStruct> { };
template <typename... Types> struct TCommonReference : TConditional<NAMESPACE_PRIVATE::CCommonReference<Types...>, NAMESPACE_PRIVATE::TCommonReference<Types...>, NAMESPACE_PRIVATE::FNoopStruct> { };
NAMESPACE_PRIVATE_BEGIN
template <typename... Ts>
// Template class declaration for the common reference implementation
template <typename...>
struct TCommonReferenceImpl;
// Template class declaration for the simple common reference Type implementation
template <typename, typename>
struct TSimpleCommonReferenceImpl;
// Template class declaration for the adding qualifiers implementation
template <typename>
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 <typename T>
struct TCommonReferenceImpl<T> { 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 <typename T, typename U> concept CSimpleCommonReference = requires { typename TSimpleCommonReferenceImpl<T, U>::Type; };
template <typename T, typename U> requires (CSimpleCommonReference<T, U>)
struct TCommonReferenceImpl<T, U> : TSimpleCommonReferenceImpl<T, U> { };
// Otherwise, if TBasicCommonReference<TRemoveCVRef<T>, TRemoveCVRef<U>, TQ, UQ>::Type exists
template <typename T, typename U> struct TBasicCommonReferenceImpl : TBasicCommonReference<TRemoveCVRef<T>, TRemoveCVRef<U>, TQualifiersImpl<T>::template Apply, TQualifiersImpl<U>::template Apply> { };
template <typename T, typename U> concept CBasicCommonReference = requires { typename TBasicCommonReferenceImpl<T, U>::Type; };
template <typename T, typename U> requires (!CSimpleCommonReference<T, U> && CBasicCommonReference<T, U>)
struct TCommonReferenceImpl<T, U> : TBasicCommonReferenceImpl<T, U>
{
// 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<T> and UQualifiers<U> are convertible
// Additionally, TBasicCommonReference<T, U, TQualifiers, UQualifiers>::Type and TBasicCommonReference<U, T, UQualifiers, TQualifiers>::Type must denote the same type
static_assert(CConvertibleTo<T, typename TBasicCommonReferenceImpl<T, U>::Type> && CConvertibleTo<U, typename TBasicCommonReferenceImpl<T, U>::Type>, "The basic common reference must be a type to which both TQualifiers<T> and UQualifiers<U> are convertible");
static_assert(CSameAs<typename TBasicCommonReferenceImpl<T, U>::Type, typename TBasicCommonReferenceImpl<U, T>::Type>, "TBasicCommonReference<T, U, TQualifiers, UQualifiers>::Type and TBasicCommonReference<U, T, UQualifiers, TQualifiers>::Type must denote the same type");
};
// Where TQ and UQ is a unary alias template such that TQ<U> is U with the addition of T's cv-ref qualifiers, then the member Type Type names that Type
template <typename T> struct TQualifiersImpl { template <typename U> using Apply = TCopyCV<T, U>; };
template <typename T> struct TQualifiersImpl<T&> { template <typename U> using Apply = TAddLValueReference<TCopyCV<T, U>>; };
template <typename T> struct TQualifiersImpl<T&&> { template <typename U> using Apply = TAddRValueReference<TCopyCV<T, U>>; };
// Otherwise, if decltype(false ? Val<T>() : Val<U>()), where val is a function template template <typename T> T Val();, is a valid Type, then the member Type Type names that Type
template <typename T> T Val();
template <typename T, typename U> concept CConditionalValType = requires { typename TVoid<decltype(false ? Val<T>() : Val<U>())>; };
template <typename T, typename U> requires (!CSimpleCommonReference<T, U> && !CBasicCommonReference<T, U> && CConditionalValType<T, U>)
struct TCommonReferenceImpl<T, U> { using Type = decltype(false ? Val<T>() : Val<U>()); };
// Otherwise, if TCommonType<T, U> is a valid Type, then the member Type Type names that Type
template <typename T, typename U> concept CCommonTypeImpl = requires { typename TCommonTypeImpl<T, U>; };
template <typename T, typename U> requires (!CSimpleCommonReference<T, U> && !CBasicCommonReference<T, U> && !CConditionalValType<T, U> && CCommonTypeImpl<T, U>)
struct TCommonReferenceImpl<T, U> : TCommonTypeImpl<T, U> { };
// Otherwise, there is no member Type.
// If sizeof...(Types) is greater than two
// If TCommonReference<T, U> exists, the member Type denotes TCommonReference<TCommonReference<T, U>, R...> if such a Type exists
template <typename T, typename U, typename W, typename... Types> requires (requires { typename TCommonReferenceImpl<T, U>::Type; })
struct TCommonReferenceImpl<T, U, W, Types...> : TCommonReferenceImpl<typename TCommonReferenceImpl<T, U>::Type, W, Types...> { };
// In all other cases, there is no member Type.
template <typename...>
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<CV12 X &>() : DeclVal<CV12 Y &>()),
// where CV12 is the union of CV1 and CV2, if that Type exists and is a reference Type
template <typename T, typename U> requires (CLValueReference<decltype(false ? DeclVal<TCopyCV<T, U>&>() : DeclVal<TCopyCV<U, T>&>())>)
struct TSimpleCommonReferenceImpl<T&, U&> { using Type = decltype(false ? DeclVal<TCopyCV<T, U>&>() : DeclVal<TCopyCV<U, T>&>()); };
// 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<T, C> and CConvertibleTo<U, C> are both true, then the simple common reference Type of T and U is C
template <typename T, typename U> requires (CConvertibleTo<T&&, TRemoveReference<typename TSimpleCommonReferenceImpl<T&, U&>::Type> &&> && CConvertibleTo<U&&, TRemoveReference<typename TSimpleCommonReferenceImpl<T&, U&>::Type> &&>)
struct TSimpleCommonReferenceImpl<T&&, U&&> { using Type = TRemoveReference<typename TSimpleCommonReferenceImpl<T&, U&>::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<B&&, D> is true, then the simple common reference Type is D
template <typename T, typename U> requires (CConvertibleTo<U&&, typename TSimpleCommonReferenceImpl<T&, const U&>::Type>)
struct TSimpleCommonReferenceImpl<T&, U&&> { using Type = typename TSimpleCommonReferenceImpl<T&, const U&>::Type; };
template <typename T, typename U> struct TSimpleCommonReferenceImpl<T&&, U&> : TSimpleCommonReferenceImpl<U&, T&&> { }; // The order is not important
// Otherwise, there's no simple common reference Type.
template <typename T, typename U>
struct TSimpleCommonReferenceImpl { };
NAMESPACE_PRIVATE_END
template <typename... Types> using TCommonType = typename NAMESPACE_PRIVATE::TCommonTypeImpl<Types...>::Type;
template <typename... Types> using TCommonReference = typename NAMESPACE_PRIVATE::TCommonReferenceImpl<Types...>::Type;
template <typename... Types>
concept CCommonReference =
requires { typename TCommonReference<Ts...>::Type; }
&& (true && ... && CConvertibleTo<Ts, typename TCommonReference<Ts...>::Type>);
requires { typename TCommonReference<Types...>; }
&& (true && ... && CConvertibleTo<Types, TCommonReference<Types...>>);
template <typename... Ts>
template <typename... Types>
concept CCommonType =
requires { typename TCommonType<Ts...>::Type; }
&& (true && ... && CConstructibleFrom<typename TCommonReference<Ts...>::Type, Ts&&>)
&& CCommonReference<const Ts&...> && CCommonReference<typename TCommonType<Ts...>::Type&, typename TCommonReference<const Ts&...>::Type>;
requires { typename TCommonType<Types...>; }
&& (true && ... && CConstructibleFrom<TCommonReference<Types...>, Types&&>)
&& CCommonReference<const Types&...> && CCommonReference<TCommonType<Types...>&, TCommonReference<const Types&...>>;
NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft)

View File

@ -22,7 +22,7 @@ concept CWeaklyEqualityComparable =
template <typename T, typename U = T>
concept CEqualityComparable = CWeaklyEqualityComparable<T> && CWeaklyEqualityComparable<U> && CWeaklyEqualityComparable<T, U>
&& CCommonReference<const TRemoveReference<T>&, const TRemoveReference<U>&>
&& CWeaklyEqualityComparable<typename TCommonReference<const TRemoveReference<T>&, const TRemoveReference<U>&>::Type>;
&& CWeaklyEqualityComparable<TCommonReference<const TRemoveReference<T>&, const TRemoveReference<U>&>>;
template <typename T, typename U = T>
concept CPartiallyOrdered =
@ -43,8 +43,8 @@ concept CTotallyOrdered =
CPartiallyOrdered<T> && CPartiallyOrdered<U>
&& CEqualityComparable<T> && CEqualityComparable<U>
&& CPartiallyOrdered<T, U> && CEqualityComparable<T, U>
&& CPartiallyOrdered<typename TCommonReference<const TRemoveReference<T>&, const TRemoveReference<U>&>::Type>
&& CEqualityComparable<typename TCommonReference<const TRemoveReference<T>&, const TRemoveReference<U>&>::Type>;
&& CPartiallyOrdered<TCommonReference<const TRemoveReference<T>&, const TRemoveReference<U>&>>
&& CEqualityComparable<TCommonReference<const TRemoveReference<T>&, const TRemoveReference<U>&>>;
NAMESPACE_MODULE_END(Utility)
NAMESPACE_MODULE_END(Redcraft)

View File

@ -41,6 +41,13 @@ template <typename T> using TRemoveCVRef = NAMESPACE_STD::remove_cvref_t<T>
template <typename T> using TRemoveExtent = NAMESPACE_STD::remove_extent_t<T>;
template <typename T> using TRemoveAllExtents = NAMESPACE_STD::remove_all_extents_t<T>;
template <typename T> using TAddConst = NAMESPACE_STD::add_const_t<T>;
template <typename T> using TAddVolatile = NAMESPACE_STD::add_volatile_t<T>;
template <typename T> using TAddCV = NAMESPACE_STD::add_cv_t<T>;
template <typename T> using TAddLValueReference = NAMESPACE_STD::add_lvalue_reference_t<T>;
template <typename T> using TAddRValueReference = NAMESPACE_STD::add_rvalue_reference_t<T>;
template <typename T> using TAddPointer = NAMESPACE_STD::add_pointer_t<T>;
template <typename T> using TMakeSigned = NAMESPACE_STD::make_signed_t<T>;
template <typename T> using TMakeUnsigned = NAMESPACE_STD::make_unsigned_t<T>;