refactor(typetraits): replaces template class type traits with alias template for TypeTraits/Common.h
This commit is contained in:
parent
c6620da1dd
commit
8b902d15a4
@ -451,13 +451,13 @@ void TestTypeTraits()
|
|||||||
|
|
||||||
// Common.h
|
// Common.h
|
||||||
|
|
||||||
always_check((CSameAs<int32, TCommonType<int8, int32>::Type>));
|
always_check((CSameAs<int32, TCommonType<int8, int32>>));
|
||||||
always_check((CSameAs<int64, TCommonType<int8, int32, int64>::Type>));
|
always_check((CSameAs<int64, TCommonType<int8, int32, int64>>));
|
||||||
always_check((CSameAs<double, TCommonType<float, double>::Type>));
|
always_check((CSameAs<double, TCommonType<float, double>>));
|
||||||
|
|
||||||
always_check((CSameAs<int32, TCommonReference<int8, int32>::Type>));
|
always_check((CSameAs<int32, TCommonReference<int8, int32>>));
|
||||||
always_check((CSameAs<int64, TCommonReference<int8, int32, int64>::Type>));
|
always_check((CSameAs<int64, TCommonReference<int8, int32, int64>>));
|
||||||
always_check((CSameAs<double, TCommonReference<float, double>::Type>));
|
always_check((CSameAs<double, TCommonReference<float, double>>));
|
||||||
|
|
||||||
always_check((CCommonType<int32, int32>));
|
always_check((CCommonType<int32, int32>));
|
||||||
always_check((CCommonType<int8, int32>));
|
always_check((CCommonType<int8, int32>));
|
||||||
|
@ -10,7 +10,7 @@ NAMESPACE_REDCRAFT_BEGIN
|
|||||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||||
NAMESPACE_MODULE_BEGIN(Utility)
|
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::partial_ordering partial_ordering;
|
||||||
typedef NAMESPACE_STD::weak_ordering weak_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>
|
concept CThreeWayComparable = CWeaklyEqualityComparable<T, U> && CPartiallyOrdered<T, U>
|
||||||
&& CCommonReference<const TRemoveReference<T>&, const TRemoveReference<U>&>
|
&& CCommonReference<const TRemoveReference<T>&, const TRemoveReference<U>&>
|
||||||
&& requires(const TRemoveReference<T>& A, const TRemoveReference<U>& B,
|
&& 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>;
|
{ A <=> A } -> CThreeWayComparesAs<OrderingType>;
|
||||||
{ B <=> B } -> CThreeWayComparesAs<OrderingType>;
|
{ B <=> B } -> CThreeWayComparesAs<OrderingType>;
|
||||||
|
@ -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)...);
|
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(Utility)
|
||||||
NAMESPACE_MODULE_END(Redcraft)
|
NAMESPACE_MODULE_END(Redcraft)
|
||||||
NAMESPACE_REDCRAFT_END
|
NAMESPACE_REDCRAFT_END
|
||||||
|
@ -39,8 +39,8 @@ constexpr size_t HashCombine(size_t A, size_t C)
|
|||||||
return C;
|
return C;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Ts> requires (true && ... && CConvertibleTo<Ts, size_t>)
|
template <typename... Types> requires (true && ... && CConvertibleTo<Types, size_t>)
|
||||||
constexpr size_t HashCombine(size_t A, size_t C, Ts... InOther)
|
constexpr size_t HashCombine(size_t A, size_t C, Types... InOther)
|
||||||
{
|
{
|
||||||
size_t B = HashCombine(A, C);
|
size_t B = HashCombine(A, C);
|
||||||
return HashCombine(B, InOther...);
|
return HashCombine(B, InOther...);
|
||||||
|
@ -236,7 +236,7 @@ struct TVariant
|
|||||||
{
|
{
|
||||||
checkf(IsValid(), TEXT("It is an error to call Visit() on an wrong TVariant. Please either check IsValid()."));
|
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*);
|
using FInvokeImpl = ReturnType(*)(F&&, void*);
|
||||||
static constexpr FInvokeImpl InvokeImpl[] = { [](F&& Func, void* This) -> ReturnType { return InvokeResult<ReturnType>(Forward<F>(Func), *reinterpret_cast<Types*>(This)); }... };
|
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()."));
|
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*);
|
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))); }... };
|
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()."));
|
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*);
|
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)); }... };
|
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()."));
|
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*);
|
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))); }... };
|
static constexpr FInvokeImpl InvokeImpl[] = { [](F&& Func, const void* This) -> ReturnType { return InvokeResult<ReturnType>(Forward<F>(Func), MoveTemp(*reinterpret_cast<const Types*>(This))); }... };
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "CoreTypes.h"
|
#include "CoreTypes.h"
|
||||||
|
#include "Templates/Utility.h"
|
||||||
|
#include "TypeTraits/PrimaryType.h"
|
||||||
#include "TypeTraits/Miscellaneous.h"
|
#include "TypeTraits/Miscellaneous.h"
|
||||||
|
#include "TypeTraits/CopyQualifiers.h"
|
||||||
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
@ -9,31 +12,179 @@ NAMESPACE_REDCRAFT_BEGIN
|
|||||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||||
NAMESPACE_MODULE_BEGIN(Utility)
|
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
|
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...>; };
|
// If sizeof...(Types) is zero, there is no member Type
|
||||||
template <typename... Types> concept CCommonReference = requires { typename NAMESPACE_STD::common_reference_t<Types...>; };
|
template <>
|
||||||
|
struct TCommonTypeImpl<> { };
|
||||||
|
|
||||||
template <typename... Types> struct TCommonType { using Type = NAMESPACE_STD::common_type_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... Types> struct TCommonReference { using Type = NAMESPACE_STD::common_reference_t<Types...>; };
|
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
|
NAMESPACE_PRIVATE_END
|
||||||
|
|
||||||
template <typename... Types> struct TCommonType : TConditional<NAMESPACE_PRIVATE::CCommonType<Types...>, NAMESPACE_PRIVATE::TCommonType<Types...>, NAMESPACE_PRIVATE::FNoopStruct> { };
|
NAMESPACE_PRIVATE_BEGIN
|
||||||
template <typename... Types> struct TCommonReference : TConditional<NAMESPACE_PRIVATE::CCommonReference<Types...>, NAMESPACE_PRIVATE::TCommonReference<Types...>, NAMESPACE_PRIVATE::FNoopStruct> { };
|
|
||||||
|
|
||||||
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 =
|
concept CCommonReference =
|
||||||
requires { typename TCommonReference<Ts...>::Type; }
|
requires { typename TCommonReference<Types...>; }
|
||||||
&& (true && ... && CConvertibleTo<Ts, typename TCommonReference<Ts...>::Type>);
|
&& (true && ... && CConvertibleTo<Types, TCommonReference<Types...>>);
|
||||||
|
|
||||||
template <typename... Ts>
|
template <typename... Types>
|
||||||
concept CCommonType =
|
concept CCommonType =
|
||||||
requires { typename TCommonType<Ts...>::Type; }
|
requires { typename TCommonType<Types...>; }
|
||||||
&& (true && ... && CConstructibleFrom<typename TCommonReference<Ts...>::Type, Ts&&>)
|
&& (true && ... && CConstructibleFrom<TCommonReference<Types...>, Types&&>)
|
||||||
&& CCommonReference<const Ts&...> && CCommonReference<typename TCommonType<Ts...>::Type&, typename TCommonReference<const Ts&...>::Type>;
|
&& CCommonReference<const Types&...> && CCommonReference<TCommonType<Types...>&, TCommonReference<const Types&...>>;
|
||||||
|
|
||||||
NAMESPACE_MODULE_END(Utility)
|
NAMESPACE_MODULE_END(Utility)
|
||||||
NAMESPACE_MODULE_END(Redcraft)
|
NAMESPACE_MODULE_END(Redcraft)
|
||||||
|
@ -22,7 +22,7 @@ concept CWeaklyEqualityComparable =
|
|||||||
template <typename T, typename U = T>
|
template <typename T, typename U = T>
|
||||||
concept CEqualityComparable = CWeaklyEqualityComparable<T> && CWeaklyEqualityComparable<U> && CWeaklyEqualityComparable<T, U>
|
concept CEqualityComparable = CWeaklyEqualityComparable<T> && CWeaklyEqualityComparable<U> && CWeaklyEqualityComparable<T, U>
|
||||||
&& CCommonReference<const TRemoveReference<T>&, const TRemoveReference<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>
|
template <typename T, typename U = T>
|
||||||
concept CPartiallyOrdered =
|
concept CPartiallyOrdered =
|
||||||
@ -43,8 +43,8 @@ concept CTotallyOrdered =
|
|||||||
CPartiallyOrdered<T> && CPartiallyOrdered<U>
|
CPartiallyOrdered<T> && CPartiallyOrdered<U>
|
||||||
&& CEqualityComparable<T> && CEqualityComparable<U>
|
&& CEqualityComparable<T> && CEqualityComparable<U>
|
||||||
&& CPartiallyOrdered<T, U> && CEqualityComparable<T, U>
|
&& CPartiallyOrdered<T, U> && CEqualityComparable<T, U>
|
||||||
&& CPartiallyOrdered<typename TCommonReference<const TRemoveReference<T>&, const TRemoveReference<U>&>::Type>
|
&& CPartiallyOrdered<TCommonReference<const TRemoveReference<T>&, const TRemoveReference<U>&>>
|
||||||
&& CEqualityComparable<typename TCommonReference<const TRemoveReference<T>&, const TRemoveReference<U>&>::Type>;
|
&& CEqualityComparable<TCommonReference<const TRemoveReference<T>&, const TRemoveReference<U>&>>;
|
||||||
|
|
||||||
NAMESPACE_MODULE_END(Utility)
|
NAMESPACE_MODULE_END(Utility)
|
||||||
NAMESPACE_MODULE_END(Redcraft)
|
NAMESPACE_MODULE_END(Redcraft)
|
||||||
|
@ -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 TRemoveExtent = NAMESPACE_STD::remove_extent_t<T>;
|
||||||
template <typename T> using TRemoveAllExtents = NAMESPACE_STD::remove_all_extents_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 TMakeSigned = NAMESPACE_STD::make_signed_t<T>;
|
||||||
template <typename T> using TMakeUnsigned = NAMESPACE_STD::make_unsigned_t<T>;
|
template <typename T> using TMakeUnsigned = NAMESPACE_STD::make_unsigned_t<T>;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user