/* Type traits for OctaSTD. * * This file is part of OctaSTD. See COPYING.md for futher information. */ #ifndef OCTA_TRAITS_H #define OCTA_TRAITS_H #include #include "octa/types.h" namespace octa { /* forward declarations */ namespace detail { template struct RemoveCv; template struct AddLr; template struct AddRr; template struct AddConst; template struct RemoveReference; template struct RemoveAllExtents; template struct CommonTypeBase; } template struct __OctaAddConst; template struct IsReference; template struct __OctaRemoveReference; template struct __OctaRemoveAllExtents; template struct IsTriviallyDefaultConstructible; template using RemoveCv = typename octa::detail::RemoveCv<_T>::Type; template using AddLvalueReference = typename octa::detail::AddLr<_T>::Type; template using AddRvalueReference = typename octa::detail::AddRr<_T>::Type; template using AddConst = typename __OctaAddConst<_T>::Type; template using RemoveReference = typename __OctaRemoveReference<_T>::Type; template using RemoveAllExtents = typename __OctaRemoveAllExtents<_T>::Type; namespace detail { template octa::AddRvalueReference<_T> declval_in(); } /* integral constant */ template struct IntegralConstant { static constexpr _T value = val; typedef _T Value; typedef IntegralConstant<_T, val> Type; constexpr operator Value() const { return value; } constexpr Value operator()() const { return value; } }; typedef IntegralConstant True; typedef IntegralConstant False; template constexpr _T IntegralConstant<_T, val>::value; /* is void */ namespace detail { template struct IsVoidBase : False {}; template< > struct IsVoidBase: True {}; } template struct IsVoid: octa::detail::IsVoidBase> {}; /* is null pointer */ namespace detail { template struct IsNullPointerBase : False {}; template< > struct IsNullPointerBase: True {}; } template struct IsNullPointer: octa::detail::IsNullPointerBase> {}; /* is integer */ namespace detail { template struct IsIntegralBase: False {}; template<> struct IsIntegralBase: True {}; template<> struct IsIntegralBase: True {}; template<> struct IsIntegralBase: True {}; template<> struct IsIntegralBase: True {}; template<> struct IsIntegralBase: True {}; template<> struct IsIntegralBase: True {}; template<> struct IsIntegralBase: True {}; template<> struct IsIntegralBase: True {}; template<> struct IsIntegralBase: True {}; template<> struct IsIntegralBase: True {}; template<> struct IsIntegralBase: True {}; template<> struct IsIntegralBase: True {}; template<> struct IsIntegralBase: True {}; template<> struct IsIntegralBase: True {}; template<> struct IsIntegralBase< wchar_t>: True {}; } template struct IsIntegral: octa::detail::IsIntegralBase> {}; /* is floating point */ namespace detail { template struct IsFloatingPointBase: False {}; template<> struct IsFloatingPointBase: True {}; template<> struct IsFloatingPointBase: True {}; template<> struct IsFloatingPointBase: True {}; } template struct IsFloatingPoint: octa::detail::IsFloatingPointBase> {}; /* is array */ template struct IsArray : False {}; template struct IsArray<_T[] >: True {}; template struct IsArray<_T[_N]>: True {}; /* is pointer */ namespace detail { template struct IsPointerBase : False {}; template struct IsPointerBase<_T *>: True {}; } template struct IsPointer: octa::detail::IsPointerBase> {}; /* is lvalue reference */ template struct IsLvalueReference : False {}; template struct IsLvalueReference<_T &>: True {}; /* is rvalue reference */ template struct IsRvalueReference : False {}; template struct IsRvalueReference<_T &&>: True {}; /* is enum */ template struct IsEnum: IntegralConstant {}; /* is union */ template struct IsUnion: IntegralConstant {}; /* is class */ template struct IsClass: IntegralConstant {}; /* is function */ namespace detail { struct FunctionTestDummy {}; template char function_test(_T *); template char function_test(FunctionTestDummy); template int function_test(...); template _T &function_source(int); template FunctionTestDummy function_source(...); template::value || octa::IsUnion<_T>::value || octa::IsVoid<_T>::value || octa::IsReference<_T>::value || octa::IsNullPointer<_T>::value > struct IsFunctionBase: IntegralConstant(function_source<_T>(0))) == 1 > {}; template struct IsFunctionBase<_T, true>: False {}; } /* namespace detail */ template struct IsFunction: octa::detail::IsFunctionBase<_T> {}; /* is arithmetic */ template struct IsArithmetic: IntegralConstant::value || IsFloatingPoint<_T>::value) > {}; /* is fundamental */ template struct IsFundamental: IntegralConstant::value || IsVoid<_T>::value || IsNullPointer<_T>::value) > {}; /* is compound */ template struct IsCompound: IntegralConstant::value > {}; /* is pointer to member */ namespace detail { template struct IsMemberPointerBase: False {}; template struct IsMemberPointerBase<_T _U::*>: True {}; } template struct IsMemberPointer: octa::detail::IsMemberPointerBase> {}; /* is pointer to member object */ namespace detail { template struct IsMemberObjectPointerBase: False {}; template struct IsMemberObjectPointerBase<_T _U::*>: IntegralConstant::value > {}; } template struct IsMemberObjectPointer: octa::detail::IsMemberObjectPointerBase> {}; /* is pointer to member function */ namespace detail { template struct IsMemberFunctionPointerBase: False {}; template struct IsMemberFunctionPointerBase<_T _U::*>: IntegralConstant::value > {}; } template struct IsMemberFunctionPointer: octa::detail::IsMemberFunctionPointerBase> {}; /* is reference */ template struct IsReference: IntegralConstant::value || IsRvalueReference<_T>::value) > {}; /* is object */ template struct IsObject: IntegralConstant::value && !IsVoid<_T>::value && !IsReference<_T>::value) > {}; /* is scalar */ template struct IsScalar: IntegralConstant::value || IsPointer<_T>::value || IsEnum<_T>::value || IsNullPointer <_T>::value || IsArithmetic<_T>::value) > {}; /* is abstract */ template struct IsAbstract: IntegralConstant {}; /* is const */ template struct IsConst : False {}; template struct IsConst: True {}; /* is volatile */ template struct IsVolatile : False {}; template struct IsVolatile: True {}; /* is empty */ template struct IsEmpty: IntegralConstant {}; /* is POD */ template struct IsPod: IntegralConstant {}; /* is polymorphic */ template struct IsPolymorphic: IntegralConstant {}; /* is signed */ template struct IsSigned: IntegralConstant {}; /* is unsigned */ template struct IsUnsigned: IntegralConstant {}; /* is standard layout */ template struct IsStandardLayout: IntegralConstant {}; /* is literal type */ template struct IsLiteralType: IntegralConstant {}; /* is trivially copyable */ template struct IsTriviallyCopyable: IntegralConstant>::value > {}; /* is trivial */ template struct IsTrivial: IntegralConstant {}; /* has virtual destructor */ template struct HasVirtualDestructor: IntegralConstant {}; /* is constructible */ namespace detail { #define OCTA_MOVE(v) static_cast &&>(v) template struct Select2nd { typedef _T Type; }; struct Any { Any(...); }; template typename Select2nd< decltype(OCTA_MOVE(_T(declval_in<_A>()...))), True >::Type is_ctible_test(_T &&, _A &&...); #undef OCTA_MOVE template False is_ctible_test(Any, _A &&...); template struct CtibleCore: CommonTypeBase< decltype(is_ctible_test(declval_in<_T>(), declval_in<_A>()...)) >::Type {}; /* function types are not constructible */ template struct CtibleCore: False {}; /* scalars are default constructible, refs are not */ template struct CtibleCore: octa::IsScalar<_T> {}; /* scalars and references are constructible from one arg if * implicitly convertible to scalar or reference */ template struct CtibleRef { static True test(_T); static False test(...); }; template struct CtibleCore: CommonTypeBase< decltype(CtibleRef<_T>::test(declval_in<_U>())) >::Type {}; /* scalars and references are not constructible from multiple args */ template struct CtibleCore: False {}; /* treat scalars and refs separately */ template struct CtibleVoidCheck: CtibleCore< (octa::IsScalar<_T>::value || octa::IsReference<_T>::value), _T, _A... > {}; /* if any of T or A is void, IsConstructible should be false */ template struct CtibleVoidCheck: False {}; template struct CtibleContainsVoid; template<> struct CtibleContainsVoid<>: False {}; template struct CtibleContainsVoid<_T, _A...> { static constexpr bool value = octa::IsVoid<_T>::value || CtibleContainsVoid<_A...>::value; }; /* entry point */ template struct Ctible: CtibleVoidCheck< CtibleContainsVoid<_T, _A...>::value || octa::IsAbstract<_T>::value, _T, _A... > {}; /* array types are default constructible if their element type is */ template struct CtibleCore: Ctible> {}; /* otherwise array types are not constructible by this syntax */ template struct CtibleCore: False {}; /* incomplete array types are not constructible */ template struct CtibleCore: False {}; } /* namespace detail */ template struct IsConstructible: octa::detail::Ctible<_T, _A...> {}; /* is default constructible */ template struct IsDefaultConstructible: IsConstructible<_T> {}; /* is copy constructible */ template struct IsCopyConstructible: IsConstructible<_T, AddLvalueReference> > {}; /* is move constructible */ template struct IsMoveConstructible: IsConstructible<_T, AddRvalueReference<_T> > {}; /* is assignable */ namespace detail { template typename octa::detail::Select2nd< decltype((declval_in<_T>() = declval_in<_U>())), True >::Type assign_test(_T &&, _U &&); template False assign_test(Any, _T &&); template::value || octa::IsVoid<_U>::value > struct IsAssignableBase: CommonTypeBase< decltype(assign_test(declval_in<_T>(), declval_in<_U>())) >::Type {}; template struct IsAssignableBase<_T, _U, true>: False {}; } /* namespace detail */ template struct IsAssignable: octa::detail::IsAssignableBase<_T, _U> {}; /* is copy assignable */ template struct IsCopyAssignable: IsAssignable< AddLvalueReference<_T>, AddLvalueReference> > {}; /* is move assignable */ template struct IsMoveAssignable: IsAssignable< AddLvalueReference<_T>, const AddRvalueReference<_T> > {}; /* is destructible */ template struct __OctaIsDtibleApply { typedef int Type; }; template struct IsDestructorWellformed { template static char __test(typename __OctaIsDtibleApply< decltype(octa::detail::declval_in<_TT &>().~_TT()) >::Type); template static int __test(...); static constexpr bool value = (sizeof(__test<_T>(12)) == sizeof(char)); }; template struct __OctaDtibleImpl; template struct __OctaDtibleImpl<_T, false>: IntegralConstant>::value > {}; template struct __OctaDtibleImpl<_T, true>: True {}; template struct __OctaDtibleFalse; template struct __OctaDtibleFalse<_T, false> : __OctaDtibleImpl<_T, IsReference<_T>::value> {}; template struct __OctaDtibleFalse<_T, true>: False {}; template struct IsDestructible: __OctaDtibleFalse<_T, IsFunction<_T>::value> {}; template struct IsDestructible<_T[]>: False {}; template< > struct IsDestructible: False {}; /* is trivially constructible */ template struct IsTriviallyConstructible: False {}; template struct IsTriviallyConstructible<_T>: IntegralConstant {}; template struct IsTriviallyConstructible<_T, _T &>: IntegralConstant {}; template struct IsTriviallyConstructible<_T, const _T &>: IntegralConstant {}; template struct IsTriviallyConstructible<_T, _T &&>: IntegralConstant {}; /* is trivially default constructible */ template struct IsTriviallyDefaultConstructible: IsTriviallyConstructible<_T> {}; /* is trivially copy constructible */ template struct IsTriviallyCopyConstructible: IsTriviallyConstructible<_T, AddLvalueReference > {}; /* is trivially move constructible */ template struct IsTriviallyMoveConstructible: IsTriviallyConstructible<_T, AddRvalueReference<_T> > {}; /* is trivially assignable */ template struct IsTriviallyAssignable: False {}; template struct IsTriviallyAssignable<_T>: IntegralConstant {}; template struct IsTriviallyAssignable<_T, _T &>: IntegralConstant {}; template struct IsTriviallyAssignable<_T, const _T &>: IntegralConstant {}; template struct IsTriviallyAssignable<_T, _T &&>: IntegralConstant {}; /* is trivially copy assignable */ template struct IsTriviallyCopyAssignable: IsTriviallyAssignable<_T, AddLvalueReference > {}; /* is trivially move assignable */ template struct IsTriviallyMoveAssignable: IsTriviallyAssignable<_T, AddRvalueReference<_T> > {}; /* is trivially destructible */ template struct IsTriviallyDestructible: IntegralConstant {}; /* is base of */ template struct IsBaseOf: IntegralConstant {}; /* is convertible */ template::value || IsFunction<_T>::value || IsArray<_T>::value > struct __OctaIsConvertible { typedef typename IsVoid<_T>::Type Type; }; template struct __OctaIsConvertible<_F, _T, false> { template static void __test_f(_TT); template(octa::detail::declval_in<_FF>())) > static True __test(int); template static False __test(...); typedef decltype(__test<_F, _T>(0)) Type; }; template struct IsConvertible: __OctaIsConvertible<_F, _T>::Type {}; /* type equality */ template struct IsSame : False {}; template struct IsSame<_T, _T>: True {}; /* extent */ template struct Extent: IntegralConstant {}; template struct Extent<_T[], 0>: IntegralConstant {}; template struct Extent<_T[], _I>: IntegralConstant::value> {}; template struct Extent<_T[_N], 0>: IntegralConstant {}; template struct Extent<_T[_N], _I>: IntegralConstant::value> {}; /* rank */ template struct Rank: IntegralConstant {}; template struct Rank<_T[]>: IntegralConstant::value + 1> {}; template struct Rank<_T[_N]>: IntegralConstant::value + 1> {}; /* remove const, volatile, cv */ template struct __OctaRemoveConst { typedef _T Type; }; template struct __OctaRemoveConst { typedef _T Type; }; template struct __OctaRemoveVolatile { typedef _T Type; }; template struct __OctaRemoveVolatile { typedef _T Type; }; template using RemoveConst = typename __OctaRemoveConst<_T>::Type; template using RemoveVolatile = typename __OctaRemoveVolatile<_T>::Type; namespace detail { template struct RemoveCv { typedef octa::RemoveVolatile> Type; }; } /* add const, volatile, cv */ template::value || IsFunction<_T>::value || IsConst<_T>::value> struct __OctaAddConstBase { typedef _T Type; }; template struct __OctaAddConstBase<_T, false> { typedef const _T Type; }; template struct __OctaAddConst { typedef typename __OctaAddConstBase<_T>::Type Type; }; template::value || IsFunction<_T>::value || IsVolatile<_T>::value> struct __OctaAddVolatileBase { typedef _T Type; }; template struct __OctaAddVolatileBase<_T, false> { typedef volatile _T Type; }; template struct __OctaAddVolatile { typedef typename __OctaAddVolatileBase<_T>::Type Type; }; template using AddVolatile = typename __OctaAddVolatile<_T>::Type; template struct __OctaAddCv { typedef AddConst> Type; }; template using AddCv = typename __OctaAddCv<_T>::Type; /* remove reference */ template struct __OctaRemoveReference { typedef _T Type; }; template struct __OctaRemoveReference<_T &> { typedef _T Type; }; template struct __OctaRemoveReference<_T &&> { typedef _T Type; }; /* remove pointer */ template struct __OctaRemovePointer { typedef _T Type; }; template struct __OctaRemovePointer<_T * > { typedef _T Type; }; template struct __OctaRemovePointer<_T * const > { typedef _T Type; }; template struct __OctaRemovePointer<_T * volatile > { typedef _T Type; }; template struct __OctaRemovePointer<_T * const volatile> { typedef _T Type; }; template using RemovePointer = typename __OctaRemovePointer<_T>::Type; /* add pointer */ template struct __OctaAddPointer { typedef RemoveReference<_T> *Type; }; template using AddPointer = typename __OctaAddPointer<_T>::Type; /* add lvalue reference */ namespace detail { template struct AddLr { typedef _T &Type; }; template struct AddLr<_T &> { typedef _T &Type; }; template struct AddLr<_T &&> { typedef _T &Type; }; template<> struct AddLr { typedef void Type; }; template<> struct AddLr { typedef const void Type; }; template<> struct AddLr { typedef volatile void Type; }; template<> struct AddLr { typedef const volatile void Type; }; } /* add rvalue reference */ namespace detail { template struct AddRr { typedef _T &&Type; }; template struct AddRr<_T &> { typedef _T &&Type; }; template struct AddRr<_T &&> { typedef _T &&Type; }; template<> struct AddRr { typedef void Type; }; template<> struct AddRr { typedef const void Type; }; template<> struct AddRr { typedef volatile void Type; }; template<> struct AddRr { typedef const volatile void Type; }; } /* remove extent */ template struct __OctaRemoveExtent { typedef _T Type; }; template struct __OctaRemoveExtent<_T[ ] > { typedef _T Type; }; template struct __OctaRemoveExtent<_T[_N]> { typedef _T Type; }; template using RemoveExtent = typename __OctaRemoveExtent<_T>::Type; /* remove all extents */ template struct __OctaRemoveAllExtents { typedef _T Type; }; template struct __OctaRemoveAllExtents<_T[]> { typedef RemoveAllExtents<_T> Type; }; template struct __OctaRemoveAllExtents<_T[_N]> { typedef RemoveAllExtents<_T> Type; }; /* make (un)signed * * this is bad, but i don't see any better way * shamelessly copied from graphitemaster @ neothyne */ namespace detail { template struct TypeList { typedef _T first; typedef _U rest; }; /* not a type */ struct TlNat { TlNat() = delete; TlNat(const TlNat &) = delete; TlNat &operator=(const TlNat &) = delete; ~TlNat() = delete; }; typedef TypeList>>>> stypes; typedef TypeList>>>> utypes; template struct TypeFindFirst; template struct TypeFindFirst, _N, true> { typedef _T Type; }; template struct TypeFindFirst, _N, false> { typedef typename TypeFindFirst<_U, _N>::Type Type; }; template>::value, bool = octa::IsVolatile>::value > struct ApplyCv { typedef _U Type; }; template struct ApplyCv<_T, _U, true, false> { /* const */ typedef const _U Type; }; template struct ApplyCv<_T, _U, false, true> { /* volatile */ typedef volatile _U Type; }; template struct ApplyCv<_T, _U, true, true> { /* const volatile */ typedef const volatile _U Type; }; template struct ApplyCv<_T &, _U, true, false> { /* const */ typedef const _U &Type; }; template struct ApplyCv<_T &, _U, false, true> { /* volatile */ typedef volatile _U &Type; }; template struct ApplyCv<_T &, _U, true, true> { /* const volatile */ typedef const volatile _U &Type; }; template::value || octa::IsEnum<_T>::value> struct MakeSigned {}; template::value || octa::IsEnum<_T>::value> struct MakeUnsigned {}; template struct MakeSigned<_T, true> { typedef typename TypeFindFirst::Type Type; }; template struct MakeUnsigned<_T, true> { typedef typename TypeFindFirst::Type Type; }; template<> struct MakeSigned {}; template<> struct MakeSigned { typedef schar Type; }; template<> struct MakeSigned { typedef schar Type; }; template<> struct MakeSigned { typedef short Type; }; template<> struct MakeSigned { typedef short Type; }; template<> struct MakeSigned { typedef int Type; }; template<> struct MakeSigned { typedef int Type; }; template<> struct MakeSigned { typedef long Type; }; template<> struct MakeSigned { typedef long Type; }; template<> struct MakeSigned { typedef llong Type; }; template<> struct MakeSigned { typedef llong Type; }; template<> struct MakeUnsigned {}; template<> struct MakeUnsigned { typedef uchar Type; }; template<> struct MakeUnsigned { typedef uchar Type; }; template<> struct MakeUnsigned { typedef ushort Type; }; template<> struct MakeUnsigned { typedef ushort Type; }; template<> struct MakeUnsigned { typedef uint Type; }; template<> struct MakeUnsigned { typedef uint Type; }; template<> struct MakeUnsigned { typedef ulong Type; }; template<> struct MakeUnsigned { typedef ulong Type; }; template<> struct MakeUnsigned { typedef ullong Type; }; template<> struct MakeUnsigned { typedef ullong Type; }; template struct MakeSignedBase { typedef typename ApplyCv<_T, typename MakeSigned>::Type >::Type Type; }; template struct MakeUnsignedBase { typedef typename ApplyCv<_T, typename MakeUnsigned>::Type >::Type Type; }; } /* namespace detail */ template using MakeSigned = typename octa::detail::MakeSignedBase<_T>::Type; template using MakeUnsigned = typename octa::detail::MakeUnsignedBase<_T>::Type; /* conditional */ namespace detail { template struct ConditionalBase { typedef _T Type; }; template struct ConditionalBase { typedef _U Type; }; } template using Conditional = typename octa::detail::ConditionalBase<_cond, _T, _U>::Type; /* result of call at compile time */ namespace detail { #define OCTA_FWD(_T, _v) static_cast<_T &&>(_v) template inline auto rof_invoke(_F &&f, _A &&...args) -> decltype(OCTA_FWD(_F, f)(OCTA_FWD(_A, args)...)) { return OCTA_FWD(_F, f)(OCTA_FWD(_A, args)...); } template inline auto rof_invoke(_T _B::*pmd, _D &&ref) -> decltype(OCTA_FWD(_D, ref).*pmd) { return OCTA_FWD(_D, ref).*pmd; } template inline auto rof_invoke(_PMD &&pmd, _P &&ptr) -> decltype((*OCTA_FWD(_P, ptr)).*OCTA_FWD(_PMD, pmd)) { return (*OCTA_FWD(_P, ptr)).*OCTA_FWD(_PMD, pmd); } template inline auto rof_invoke(_T _B::*pmf, _D &&ref, _A &&...args) -> decltype((OCTA_FWD(_D, ref).*pmf)(OCTA_FWD(_A, args)...)) { return (OCTA_FWD(_D, ref).*pmf)(OCTA_FWD(_A, args)...); } template inline auto rof_invoke(_PMF &&pmf, _P &&ptr, _A &&...args) -> decltype(((*OCTA_FWD(_P, ptr)).*OCTA_FWD(_PMF, pmf)) (OCTA_FWD(_A, args)...)) { return ((*OCTA_FWD(_P, ptr)).*OCTA_FWD(_PMF, pmf)) (OCTA_FWD(_A, args)...); } #undef OCTA_FWD template struct ResultOfCore {}; template struct ResultOfCore<_F(_A...), decltype(void(rof_invoke( octa::detail::declval_in<_F>(), octa::detail::declval_in<_A>()...)))> { using type = decltype(rof_invoke(octa::detail::declval_in<_F>(), octa::detail::declval_in<_A>()...)); }; template struct ResultOfBase: ResultOfCore<_T> {}; } /* namespace detail */ template using ResultOf = typename octa::detail::ResultOfBase<_T>::Type; /* enable if */ namespace detail { template struct EnableIfBase {}; template struct EnableIfBase { typedef _T Type; }; } template using EnableIf = typename octa::detail::EnableIfBase<_B, _T>::Type; /* decay */ namespace detail { template struct DecayBase { private: typedef octa::RemoveReference<_T> _U; public: typedef octa::Conditional::value, octa::RemoveExtent<_U> *, octa::Conditional::value, octa::AddPointer<_U>, octa::RemoveCv<_U>> > Type; }; } template using Decay = typename octa::detail::DecayBase<_T>::Type; /* common type */ namespace detail { template struct CommonTypeBase; template struct CommonTypeBase<_T> { typedef Decay<_T> Type; }; template struct CommonTypeBase<_T, _U> { typedef Decay() : octa::detail::declval_in<_U>())> Type; }; template struct CommonTypeBase<_T, _U, _V...> { typedef typename CommonTypeBase::Type, _V...>::Type Type; }; } template using CommonType = typename octa::detail::CommonTypeBase<_T, _U, _V...>::Type; /* aligned storage */ template struct __OctaAlignedTest { union type { uchar __data[_N]; octa::max_align_t __align; }; }; template struct __OctaAlignedStorage { struct type { alignas(_A) uchar __data[_N]; }; }; template::Type) > using AlignedStorage = typename __OctaAlignedStorage<_N, _A>::Type; /* aligned union */ template struct __OctaAlignMax; template struct __OctaAlignMax<_N> { static constexpr size_t value = _N; }; template struct __OctaAlignMax<_N1, _N2> { static constexpr size_t value = (_N1 > _N2) ? _N1 : _N2; }; template struct __OctaAlignMax<_N1, _N2, _N...> { static constexpr size_t value = __OctaAlignMax<__OctaAlignMax<_N1, _N2>::value, _N...>::value; }; template struct __OctaAlignedUnion { static constexpr size_t __alignment_value = __OctaAlignMax::value; struct type { alignas(__alignment_value) uchar __data[__OctaAlignMax<_N, sizeof(_T)...>::value]; }; }; template using AlignedUnion = typename __OctaAlignedUnion<_N, _T...>::Type; /* underlying type */ /* gotta wrap, in a struct otherwise clang ICEs... */ template struct __OctaUnderlyingType { typedef __underlying_type(_T) Type; }; template using UnderlyingType = typename __OctaUnderlyingType<_T>::Type; } #endif