michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=8 sts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* Template-based metaprogramming and type-testing facilities. */ michael@0: michael@0: #ifndef mozilla_TypeTraits_h michael@0: #define mozilla_TypeTraits_h michael@0: michael@0: #include "mozilla/Types.h" michael@0: michael@0: /* michael@0: * These traits are approximate copies of the traits and semantics from C++11's michael@0: * header. Don't add traits not in that header! When all michael@0: * platforms provide that header, we can convert all users and remove this one. michael@0: */ michael@0: michael@0: #include michael@0: michael@0: namespace mozilla { michael@0: michael@0: /* Forward declarations. */ michael@0: michael@0: template struct RemoveCV; michael@0: michael@0: /* 20.9.3 Helper classes [meta.help] */ michael@0: michael@0: /** michael@0: * Helper class used as a base for various type traits, exposed publicly michael@0: * because exposes it as well. michael@0: */ michael@0: template michael@0: struct IntegralConstant michael@0: { michael@0: static const T value = Value; michael@0: typedef T ValueType; michael@0: typedef IntegralConstant Type; michael@0: }; michael@0: michael@0: /** Convenient aliases. */ michael@0: typedef IntegralConstant TrueType; michael@0: typedef IntegralConstant FalseType; michael@0: michael@0: /* 20.9.4 Unary type traits [meta.unary] */ michael@0: michael@0: /* 20.9.4.1 Primary type categories [meta.unary.cat] */ michael@0: michael@0: namespace detail { michael@0: michael@0: template michael@0: struct IsIntegralHelper : FalseType {}; michael@0: michael@0: template<> struct IsIntegralHelper : TrueType {}; michael@0: template<> struct IsIntegralHelper : TrueType {}; michael@0: template<> struct IsIntegralHelper : TrueType {}; michael@0: template<> struct IsIntegralHelper : TrueType {}; michael@0: template<> struct IsIntegralHelper : TrueType {}; michael@0: template<> struct IsIntegralHelper : TrueType {}; michael@0: template<> struct IsIntegralHelper : TrueType {}; michael@0: template<> struct IsIntegralHelper : TrueType {}; michael@0: template<> struct IsIntegralHelper : TrueType {}; michael@0: template<> struct IsIntegralHelper : TrueType {}; michael@0: template<> struct IsIntegralHelper : TrueType {}; michael@0: template<> struct IsIntegralHelper : TrueType {}; michael@0: template<> struct IsIntegralHelper : TrueType {}; michael@0: #ifdef MOZ_CHAR16_IS_NOT_WCHAR michael@0: template<> struct IsIntegralHelper : TrueType {}; michael@0: #endif michael@0: michael@0: } /* namespace detail */ michael@0: michael@0: /** michael@0: * IsIntegral determines whether a type is an integral type. michael@0: * michael@0: * mozilla::IsIntegral::value is true; michael@0: * mozilla::IsIntegral::value is true; michael@0: * mozilla::IsIntegral::value is true; michael@0: * mozilla::IsIntegral::value is false; michael@0: * mozilla::IsIntegral::value is false; michael@0: * michael@0: * Note that the behavior of IsIntegral on char16_t and char32_t is michael@0: * unspecified. michael@0: */ michael@0: template michael@0: struct IsIntegral : detail::IsIntegralHelper::Type> michael@0: {}; michael@0: michael@0: template michael@0: struct IsSame; michael@0: michael@0: namespace detail { michael@0: michael@0: template michael@0: struct IsFloatingPointHelper michael@0: : IntegralConstant::value || michael@0: IsSame::value || michael@0: IsSame::value> michael@0: {}; michael@0: michael@0: } // namespace detail michael@0: michael@0: /** michael@0: * IsFloatingPoint determines whether a type is a floating point type (float, michael@0: * double, long double). michael@0: * michael@0: * mozilla::IsFloatingPoint::value is false; michael@0: * mozilla::IsFloatingPoint::value is true; michael@0: * mozilla::IsFloatingPoint::value is true; michael@0: * mozilla::IsFloatingPoint::value is false. michael@0: */ michael@0: template michael@0: struct IsFloatingPoint michael@0: : detail::IsFloatingPointHelper::Type> michael@0: {}; michael@0: michael@0: namespace detail { michael@0: michael@0: template michael@0: struct IsArrayHelper : FalseType {}; michael@0: michael@0: template michael@0: struct IsArrayHelper : TrueType {}; michael@0: michael@0: template michael@0: struct IsArrayHelper : TrueType {}; michael@0: michael@0: } // namespace detail michael@0: michael@0: /** michael@0: * IsArray determines whether a type is an array type, of known or unknown michael@0: * length. michael@0: * michael@0: * mozilla::IsArray::value is false; michael@0: * mozilla::IsArray::value is true; michael@0: * mozilla::IsArray::value is true. michael@0: */ michael@0: template michael@0: struct IsArray : detail::IsArrayHelper::Type> michael@0: {}; michael@0: michael@0: /** michael@0: * IsPointer determines whether a type is a pointer type (but not a pointer-to- michael@0: * member type). michael@0: * michael@0: * mozilla::IsPointer::value is true; michael@0: * mozilla::IsPointer::value is true; michael@0: * mozilla::IsPointer::value is true; michael@0: * mozilla::IsPointer::value is false; michael@0: * mozilla::IsPointer::value is false. michael@0: */ michael@0: template michael@0: struct IsPointer : FalseType {}; michael@0: michael@0: template michael@0: struct IsPointer : TrueType {}; michael@0: michael@0: /** michael@0: * IsLvalueReference determines whether a type is an lvalue reference. michael@0: * michael@0: * mozilla::IsLvalueReference::value is false; michael@0: * mozilla::IsLvalueReference::value is false; michael@0: * mozilla::IsLvalueReference::value is false; michael@0: * mozilla::IsLvalueReference::value is false; michael@0: * mozilla::IsLvalueReference::value is false; michael@0: * mozilla::IsLvalueReference::value is true; michael@0: * mozilla::IsLvalueReference::value is false. michael@0: */ michael@0: template michael@0: struct IsLvalueReference : FalseType {}; michael@0: michael@0: template michael@0: struct IsLvalueReference : TrueType {}; michael@0: michael@0: /** michael@0: * IsRvalueReference determines whether a type is an rvalue reference. michael@0: * michael@0: * mozilla::IsRvalueReference::value is false; michael@0: * mozilla::IsRvalueReference::value is false; michael@0: * mozilla::IsRvalueReference::value is false; michael@0: * mozilla::IsRvalueReference::value is false; michael@0: * mozilla::IsRvalueReference::value is false; michael@0: * mozilla::IsRvalueReference::value is false; michael@0: * mozilla::IsRvalueReference::value is true. michael@0: */ michael@0: template michael@0: struct IsRvalueReference : FalseType {}; michael@0: michael@0: template michael@0: struct IsRvalueReference : TrueType {}; michael@0: michael@0: namespace detail { michael@0: michael@0: // __is_enum is a supported extension across all of our supported compilers. michael@0: template michael@0: struct IsEnumHelper michael@0: : IntegralConstant michael@0: {}; michael@0: michael@0: } // namespace detail michael@0: michael@0: /** michael@0: * IsEnum determines whether a type is an enum type. michael@0: * michael@0: * mozilla::IsEnum::value is true; michael@0: * mozilla::IsEnum::value is false; michael@0: * mozilla::IsEnum::value is false; michael@0: */ michael@0: template michael@0: struct IsEnum michael@0: : detail::IsEnumHelper::Type> michael@0: {}; michael@0: michael@0: namespace detail { michael@0: michael@0: // __is_class is a supported extension across all of our supported compilers: michael@0: // http://llvm.org/releases/3.0/docs/ClangReleaseNotes.html michael@0: // http://gcc.gnu.org/onlinedocs/gcc-4.4.7/gcc/Type-Traits.html#Type-Traits michael@0: // http://msdn.microsoft.com/en-us/library/ms177194%28v=vs.100%29.aspx michael@0: template michael@0: struct IsClassHelper michael@0: : IntegralConstant michael@0: {}; michael@0: michael@0: } // namespace detail michael@0: michael@0: /** michael@0: * IsClass determines whether a type is a class type (but not a union). michael@0: * michael@0: * struct S {}; michael@0: * union U {}; michael@0: * mozilla::IsClass::value is false; michael@0: * mozilla::IsClass::value is true; michael@0: * mozilla::IsClass::value is false; michael@0: */ michael@0: template michael@0: struct IsClass michael@0: : detail::IsClassHelper::Type> michael@0: {}; michael@0: michael@0: /* 20.9.4.2 Composite type traits [meta.unary.comp] */ michael@0: michael@0: /** michael@0: * IsReference determines whether a type is an lvalue or rvalue reference. michael@0: * michael@0: * mozilla::IsReference::value is false; michael@0: * mozilla::IsReference::value is false; michael@0: * mozilla::IsReference::value is true; michael@0: * mozilla::IsReference::value is false; michael@0: * mozilla::IsReference::value is true; michael@0: * mozilla::IsReference::value is false; michael@0: * mozilla::IsReference::value is false; michael@0: * mozilla::IsReference::value is true; michael@0: * mozilla::IsReference::value is true; michael@0: * mozilla::IsReference::value is true. michael@0: */ michael@0: template michael@0: struct IsReference michael@0: : IntegralConstant::value || IsRvalueReference::value> michael@0: {}; michael@0: michael@0: /** michael@0: * IsArithmetic determines whether a type is arithmetic. A type is arithmetic michael@0: * iff it is an integral type or a floating point type. michael@0: * michael@0: * mozilla::IsArithmetic::value is true; michael@0: * mozilla::IsArithmetic::value is true; michael@0: * mozilla::IsArithmetic::value is false. michael@0: */ michael@0: template michael@0: struct IsArithmetic michael@0: : IntegralConstant::value || IsFloatingPoint::value> michael@0: {}; michael@0: michael@0: /* 20.9.4.3 Type properties [meta.unary.prop] */ michael@0: michael@0: /** michael@0: * IsConst determines whether a type is const or not. michael@0: * michael@0: * mozilla::IsConst::value is false; michael@0: * mozilla::IsConst::value is true; michael@0: * mozilla::IsConst::value is false. michael@0: */ michael@0: template michael@0: struct IsConst : FalseType {}; michael@0: michael@0: template michael@0: struct IsConst : TrueType {}; michael@0: michael@0: /** michael@0: * IsVolatile determines whether a type is volatile or not. michael@0: * michael@0: * mozilla::IsVolatile::value is false; michael@0: * mozilla::IsVolatile::value is true; michael@0: * mozilla::IsVolatile::value is false. michael@0: */ michael@0: template michael@0: struct IsVolatile : FalseType {}; michael@0: michael@0: template michael@0: struct IsVolatile : TrueType {}; michael@0: michael@0: /** michael@0: * Traits class for identifying POD types. Until C++11 there's no automatic michael@0: * way to detect PODs, so for the moment this is done manually. Users may michael@0: * define specializations of this class that inherit from mozilla::TrueType and michael@0: * mozilla::FalseType (or equivalently mozilla::IntegralConstant, or conveniently from mozilla::IsPod for composite types) as needed to michael@0: * ensure correct IsPod behavior. michael@0: */ michael@0: template michael@0: struct IsPod : public FalseType {}; michael@0: michael@0: template<> struct IsPod : TrueType {}; michael@0: template<> struct IsPod : TrueType {}; michael@0: template<> struct IsPod : TrueType {}; michael@0: template<> struct IsPod : TrueType {}; michael@0: template<> struct IsPod : TrueType {}; michael@0: template<> struct IsPod : TrueType {}; michael@0: template<> struct IsPod : TrueType {}; michael@0: template<> struct IsPod : TrueType {}; michael@0: template<> struct IsPod : TrueType {}; michael@0: template<> struct IsPod : TrueType {}; michael@0: template<> struct IsPod : TrueType {}; michael@0: template<> struct IsPod : TrueType {}; michael@0: template<> struct IsPod : TrueType {}; michael@0: template<> struct IsPod : TrueType {}; michael@0: template<> struct IsPod : TrueType {}; michael@0: #ifdef MOZ_CHAR16_IS_NOT_WCHAR michael@0: template<> struct IsPod : TrueType {}; michael@0: #endif michael@0: template struct IsPod : TrueType {}; michael@0: michael@0: namespace detail { michael@0: michael@0: // __is_empty is a supported extension across all of our supported compilers: michael@0: // http://llvm.org/releases/3.0/docs/ClangReleaseNotes.html michael@0: // http://gcc.gnu.org/onlinedocs/gcc-4.4.7/gcc/Type-Traits.html#Type-Traits michael@0: // http://msdn.microsoft.com/en-us/library/ms177194%28v=vs.100%29.aspx michael@0: template michael@0: struct IsEmptyHelper michael@0: : IntegralConstant::value && __is_empty(T)> michael@0: {}; michael@0: michael@0: } // namespace detail michael@0: michael@0: /** michael@0: * IsEmpty determines whether a type is a class (but not a union) that is empty. michael@0: * michael@0: * A class is empty iff it and all its base classes have no non-static data michael@0: * members (except bit-fields of length 0) and no virtual member functions, and michael@0: * no base class is empty or a virtual base class. michael@0: * michael@0: * Intuitively, empty classes don't have any data that has to be stored in michael@0: * instances of those classes. (The size of the class must still be non-zero, michael@0: * because distinct array elements of any type must have different addresses. michael@0: * However, if the Empty Base Optimization is implemented by the compiler [most michael@0: * compilers implement it, and in certain cases C++11 requires it], the size of michael@0: * a class inheriting from an empty |Base| class need not be inflated by michael@0: * |sizeof(Base)|.) And intuitively, non-empty classes have data members and/or michael@0: * vtable pointers that must be stored in each instance for proper behavior. michael@0: * michael@0: * static_assert(!mozilla::IsEmpty::value, "not a class => not empty"); michael@0: * union U1 { int x; }; michael@0: * static_assert(!mozilla::IsEmpty::value, "not a class => not empty"); michael@0: * struct E1 {}; michael@0: * struct E2 { int : 0 }; michael@0: * struct E3 : E1 {}; michael@0: * struct E4 : E2 {}; michael@0: * static_assert(mozilla::IsEmpty::value && michael@0: * mozilla::IsEmpty::value && michael@0: * mozilla::IsEmpty::value && michael@0: * mozilla::IsEmpty::value, michael@0: * "all empty"); michael@0: * union U2 { E1 e1; }; michael@0: * static_assert(!mozilla::IsEmpty::value, "not a class => not empty"); michael@0: * struct NE1 { int x; }; michael@0: * struct NE2 : virtual E1 {}; michael@0: * struct NE3 : E2 { virtual ~NE3() {} }; michael@0: * struct NE4 { virtual void f() {} }; michael@0: * static_assert(!mozilla::IsEmpty::value && michael@0: * !mozilla::IsEmpty::value && michael@0: * !mozilla::IsEmpty::value && michael@0: * !mozilla::IsEmpty::value, michael@0: * "all empty"); michael@0: */ michael@0: template michael@0: struct IsEmpty : detail::IsEmptyHelper::Type> michael@0: {}; michael@0: michael@0: michael@0: namespace detail { michael@0: michael@0: template::value> michael@0: struct IsSignedHelper; michael@0: michael@0: template michael@0: struct IsSignedHelper : TrueType {}; michael@0: michael@0: template michael@0: struct IsSignedHelper michael@0: : IntegralConstant::value && T(-1) < T(1)> michael@0: {}; michael@0: michael@0: } // namespace detail michael@0: michael@0: /** michael@0: * IsSigned determines whether a type is a signed arithmetic type. |char| is michael@0: * considered a signed type if it has the same representation as |signed char|. michael@0: * michael@0: * Don't use this if the type might be user-defined! You might or might not get michael@0: * a compile error, depending. michael@0: * michael@0: * mozilla::IsSigned::value is true; michael@0: * mozilla::IsSigned::value is false; michael@0: * mozilla::IsSigned::value is false; michael@0: * mozilla::IsSigned::value is true. michael@0: */ michael@0: template michael@0: struct IsSigned : detail::IsSignedHelper {}; michael@0: michael@0: namespace detail { michael@0: michael@0: template::value> michael@0: struct IsUnsignedHelper; michael@0: michael@0: template michael@0: struct IsUnsignedHelper : FalseType {}; michael@0: michael@0: template michael@0: struct IsUnsignedHelper michael@0: : IntegralConstant::value && michael@0: (IsSame::Type, bool>::value || michael@0: T(1) < T(-1))> michael@0: {}; michael@0: michael@0: } // namespace detail michael@0: michael@0: /** michael@0: * IsUnsigned determines whether a type is an unsigned arithmetic type. michael@0: * michael@0: * Don't use this if the type might be user-defined! You might or might not get michael@0: * a compile error, depending. michael@0: * michael@0: * mozilla::IsUnsigned::value is false; michael@0: * mozilla::IsUnsigned::value is true; michael@0: * mozilla::IsUnsigned::value is true; michael@0: * mozilla::IsUnsigned::value is false. michael@0: */ michael@0: template michael@0: struct IsUnsigned : detail::IsUnsignedHelper {}; michael@0: michael@0: /* 20.9.5 Type property queries [meta.unary.prop.query] */ michael@0: michael@0: /* 20.9.6 Relationships between types [meta.rel] */ michael@0: michael@0: /** michael@0: * IsSame tests whether two types are the same type. michael@0: * michael@0: * mozilla::IsSame::value is true; michael@0: * mozilla::IsSame::value is true; michael@0: * mozilla::IsSame::value is false; michael@0: * mozilla::IsSame::value is true; michael@0: * mozilla::IsSame::value is false; michael@0: * mozilla::IsSame::value is true. michael@0: */ michael@0: template michael@0: struct IsSame : FalseType {}; michael@0: michael@0: template michael@0: struct IsSame : TrueType {}; michael@0: michael@0: namespace detail { michael@0: michael@0: #if defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER) michael@0: michael@0: template michael@0: struct BaseOfTester : IntegralConstant {}; michael@0: michael@0: #else michael@0: michael@0: // The trickery used to implement IsBaseOf here makes it possible to use it for michael@0: // the cases of private and multiple inheritance. This code was inspired by the michael@0: // sample code here: michael@0: // michael@0: // http://stackoverflow.com/questions/2910979/how-is-base-of-works michael@0: template michael@0: struct BaseOfHelper michael@0: { michael@0: public: michael@0: operator Base*() const; michael@0: operator Derived*(); michael@0: }; michael@0: michael@0: template michael@0: struct BaseOfTester michael@0: { michael@0: private: michael@0: template michael@0: static char test(Derived*, T); michael@0: static int test(Base*, int); michael@0: michael@0: public: michael@0: static const bool value = michael@0: sizeof(test(BaseOfHelper(), int())) == sizeof(char); michael@0: }; michael@0: michael@0: template michael@0: struct BaseOfTester michael@0: { michael@0: private: michael@0: template michael@0: static char test(Derived*, T); michael@0: static int test(Base*, int); michael@0: michael@0: public: michael@0: static const bool value = michael@0: sizeof(test(BaseOfHelper(), int())) == sizeof(char); michael@0: }; michael@0: michael@0: template michael@0: struct BaseOfTester : FalseType {}; michael@0: michael@0: template michael@0: struct BaseOfTester : TrueType {}; michael@0: michael@0: template michael@0: struct BaseOfTester : TrueType {}; michael@0: michael@0: #endif michael@0: michael@0: } /* namespace detail */ michael@0: michael@0: /* michael@0: * IsBaseOf allows to know whether a given class is derived from another. michael@0: * michael@0: * Consider the following class definitions: michael@0: * michael@0: * class A {}; michael@0: * class B : public A {}; michael@0: * class C {}; michael@0: * michael@0: * mozilla::IsBaseOf::value is true; michael@0: * mozilla::IsBaseOf::value is false; michael@0: */ michael@0: template michael@0: struct IsBaseOf michael@0: : IntegralConstant::value> michael@0: {}; michael@0: michael@0: namespace detail { michael@0: michael@0: template michael@0: struct ConvertibleTester michael@0: { michael@0: private: michael@0: static From create(); michael@0: michael@0: template michael@0: static char test(To to); michael@0: michael@0: template michael@0: static int test(...); michael@0: michael@0: public: michael@0: static const bool value = michael@0: sizeof(test(create())) == sizeof(char); michael@0: }; michael@0: michael@0: } // namespace detail michael@0: michael@0: /** michael@0: * IsConvertible determines whether a value of type From will implicitly convert michael@0: * to a value of type To. For example: michael@0: * michael@0: * struct A {}; michael@0: * struct B : public A {}; michael@0: * struct C {}; michael@0: * michael@0: * mozilla::IsConvertible::value is true; michael@0: * mozilla::IsConvertible::value is true; michael@0: * mozilla::IsConvertible::value is true; michael@0: * mozilla::IsConvertible::value is true; michael@0: * mozilla::IsConvertible::value is false; michael@0: * mozilla::IsConvertible::value is false; michael@0: * mozilla::IsConvertible::value is false; michael@0: * mozilla::IsConvertible::value is false. michael@0: * michael@0: * For obscure reasons, you can't use IsConvertible when the types being tested michael@0: * are related through private inheritance, and you'll get a compile error if michael@0: * you try. Just don't do it! michael@0: */ michael@0: template michael@0: struct IsConvertible michael@0: : IntegralConstant::value> michael@0: {}; michael@0: michael@0: /* 20.9.7 Transformations between types [meta.trans] */ michael@0: michael@0: /* 20.9.7.1 Const-volatile modifications [meta.trans.cv] */ michael@0: michael@0: /** michael@0: * RemoveConst removes top-level const qualifications on a type. michael@0: * michael@0: * mozilla::RemoveConst::Type is int; michael@0: * mozilla::RemoveConst::Type is int; michael@0: * mozilla::RemoveConst::Type is const int*; michael@0: * mozilla::RemoveConst::Type is int*. michael@0: */ michael@0: template michael@0: struct RemoveConst michael@0: { michael@0: typedef T Type; michael@0: }; michael@0: michael@0: template michael@0: struct RemoveConst michael@0: { michael@0: typedef T Type; michael@0: }; michael@0: michael@0: /** michael@0: * RemoveVolatile removes top-level volatile qualifications on a type. michael@0: * michael@0: * mozilla::RemoveVolatile::Type is int; michael@0: * mozilla::RemoveVolatile::Type is int; michael@0: * mozilla::RemoveVolatile::Type is volatile int*; michael@0: * mozilla::RemoveVolatile::Type is int*. michael@0: */ michael@0: template michael@0: struct RemoveVolatile michael@0: { michael@0: typedef T Type; michael@0: }; michael@0: michael@0: template michael@0: struct RemoveVolatile michael@0: { michael@0: typedef T Type; michael@0: }; michael@0: michael@0: /** michael@0: * RemoveCV removes top-level const and volatile qualifications on a type. michael@0: * michael@0: * mozilla::RemoveCV::Type is int; michael@0: * mozilla::RemoveCV::Type is int; michael@0: * mozilla::RemoveCV::Type is int; michael@0: * mozilla::RemoveCV::Type is int*. michael@0: */ michael@0: template michael@0: struct RemoveCV michael@0: { michael@0: typedef typename RemoveConst::Type>::Type Type; michael@0: }; michael@0: michael@0: /* 20.9.7.2 Reference modifications [meta.trans.ref] */ michael@0: michael@0: /** michael@0: * Converts reference types to the underlying types. michael@0: * michael@0: * mozilla::RemoveReference::Type is T; michael@0: * mozilla::RemoveReference::Type is T; michael@0: * mozilla::RemoveReference::Type is T; michael@0: */ michael@0: michael@0: template michael@0: struct RemoveReference michael@0: { michael@0: typedef T Type; michael@0: }; michael@0: michael@0: template michael@0: struct RemoveReference michael@0: { michael@0: typedef T Type; michael@0: }; michael@0: michael@0: template michael@0: struct RemoveReference michael@0: { michael@0: typedef T Type; michael@0: }; michael@0: michael@0: /* 20.9.7.3 Sign modifications [meta.trans.sign] */ michael@0: michael@0: template michael@0: struct EnableIf; michael@0: michael@0: template michael@0: struct Conditional; michael@0: michael@0: namespace detail { michael@0: michael@0: template michael@0: struct WithC : Conditional michael@0: {}; michael@0: michael@0: template michael@0: struct WithV : Conditional michael@0: {}; michael@0: michael@0: michael@0: template michael@0: struct WithCV : WithC::Type> michael@0: {}; michael@0: michael@0: template michael@0: struct CorrespondingSigned; michael@0: michael@0: template<> michael@0: struct CorrespondingSigned { typedef signed char Type; }; michael@0: template<> michael@0: struct CorrespondingSigned { typedef signed char Type; }; michael@0: template<> michael@0: struct CorrespondingSigned { typedef short Type; }; michael@0: template<> michael@0: struct CorrespondingSigned { typedef int Type; }; michael@0: template<> michael@0: struct CorrespondingSigned { typedef long Type; }; michael@0: template<> michael@0: struct CorrespondingSigned { typedef long long Type; }; michael@0: michael@0: template::Type, michael@0: bool IsSignedIntegerType = IsSigned::value && michael@0: !IsSame::value> michael@0: struct MakeSigned; michael@0: michael@0: template michael@0: struct MakeSigned michael@0: { michael@0: typedef T Type; michael@0: }; michael@0: michael@0: template michael@0: struct MakeSigned michael@0: : WithCV::value, IsVolatile::value, michael@0: typename CorrespondingSigned::Type> michael@0: {}; michael@0: michael@0: } // namespace detail michael@0: michael@0: /** michael@0: * MakeSigned produces the corresponding signed integer type for a given michael@0: * integral type T, with the const/volatile qualifiers of T. T must be a michael@0: * possibly-const/volatile-qualified integral type that isn't bool. michael@0: * michael@0: * If T is already a signed integer type (not including char!), then T is michael@0: * produced. michael@0: * michael@0: * Otherwise, if T is an unsigned integer type, the signed variety of T, with michael@0: * T's const/volatile qualifiers, is produced. michael@0: * michael@0: * Otherwise, the integral type of the same size as T, with the lowest rank, michael@0: * with T's const/volatile qualifiers, is produced. (This basically only acts michael@0: * to produce signed char when T = char.) michael@0: * michael@0: * mozilla::MakeSigned::Type is signed long; michael@0: * mozilla::MakeSigned::Type is volatile int; michael@0: * mozilla::MakeSigned::Type is const signed short; michael@0: * mozilla::MakeSigned::Type is const signed char; michael@0: * mozilla::MakeSigned is an error; michael@0: * mozilla::MakeSigned is an error. michael@0: */ michael@0: template michael@0: struct MakeSigned michael@0: : EnableIf::value && !IsSame::Type>::value, michael@0: typename detail::MakeSigned michael@0: >::Type michael@0: {}; michael@0: michael@0: namespace detail { michael@0: michael@0: template michael@0: struct CorrespondingUnsigned; michael@0: michael@0: template<> michael@0: struct CorrespondingUnsigned { typedef unsigned char Type; }; michael@0: template<> michael@0: struct CorrespondingUnsigned { typedef unsigned char Type; }; michael@0: template<> michael@0: struct CorrespondingUnsigned { typedef unsigned short Type; }; michael@0: template<> michael@0: struct CorrespondingUnsigned { typedef unsigned int Type; }; michael@0: template<> michael@0: struct CorrespondingUnsigned { typedef unsigned long Type; }; michael@0: template<> michael@0: struct CorrespondingUnsigned { typedef unsigned long long Type; }; michael@0: michael@0: michael@0: template::Type, michael@0: bool IsUnsignedIntegerType = IsUnsigned::value && michael@0: !IsSame::value> michael@0: struct MakeUnsigned; michael@0: michael@0: template michael@0: struct MakeUnsigned michael@0: { michael@0: typedef T Type; michael@0: }; michael@0: michael@0: template michael@0: struct MakeUnsigned michael@0: : WithCV::value, IsVolatile::value, michael@0: typename CorrespondingUnsigned::Type> michael@0: {}; michael@0: michael@0: } // namespace detail michael@0: michael@0: /** michael@0: * MakeUnsigned produces the corresponding unsigned integer type for a given michael@0: * integral type T, with the const/volatile qualifiers of T. T must be a michael@0: * possibly-const/volatile-qualified integral type that isn't bool. michael@0: * michael@0: * If T is already an unsigned integer type (not including char!), then T is michael@0: * produced. michael@0: * michael@0: * Otherwise, if T is an signed integer type, the unsigned variety of T, with michael@0: * T's const/volatile qualifiers, is produced. michael@0: * michael@0: * Otherwise, the unsigned integral type of the same size as T, with the lowest michael@0: * rank, with T's const/volatile qualifiers, is produced. (This basically only michael@0: * acts to produce unsigned char when T = char.) michael@0: * michael@0: * mozilla::MakeUnsigned::Type is unsigned long; michael@0: * mozilla::MakeUnsigned::Type is volatile unsigned int; michael@0: * mozilla::MakeUnsigned::Type is const unsigned short; michael@0: * mozilla::MakeUnsigned::Type is const unsigned char; michael@0: * mozilla::MakeUnsigned is an error; michael@0: * mozilla::MakeUnsigned is an error. michael@0: */ michael@0: template michael@0: struct MakeUnsigned michael@0: : EnableIf::value && !IsSame::Type>::value, michael@0: typename detail::MakeUnsigned michael@0: >::Type michael@0: {}; michael@0: michael@0: /* 20.9.7.4 Array modifications [meta.trans.arr] */ michael@0: michael@0: /* 20.9.7.5 Pointer modifications [meta.trans.ptr] */ michael@0: michael@0: /* 20.9.7.6 Other transformations [meta.trans.other] */ michael@0: michael@0: /** michael@0: * EnableIf is a struct containing a typedef of T if and only if B is true. michael@0: * michael@0: * mozilla::EnableIf::Type is int; michael@0: * mozilla::EnableIf::Type is a compile-time error. michael@0: * michael@0: * Use this template to implement SFINAE-style (Substitution Failure Is not An michael@0: * Error) requirements. For example, you might use it to impose a restriction michael@0: * on a template parameter: michael@0: * michael@0: * template michael@0: * class PodVector // vector optimized to store POD (memcpy-able) types michael@0: * { michael@0: * EnableIf::value, T>::Type* vector; michael@0: * size_t length; michael@0: * ... michael@0: * }; michael@0: */ michael@0: template michael@0: struct EnableIf michael@0: {}; michael@0: michael@0: template michael@0: struct EnableIf michael@0: { michael@0: typedef T Type; michael@0: }; michael@0: michael@0: /** michael@0: * Conditional selects a class between two, depending on a given boolean value. michael@0: * michael@0: * mozilla::Conditional::Type is A; michael@0: * mozilla::Conditional::Type is B; michael@0: */ michael@0: template michael@0: struct Conditional michael@0: { michael@0: typedef A Type; michael@0: }; michael@0: michael@0: template michael@0: struct Conditional michael@0: { michael@0: typedef B Type; michael@0: }; michael@0: michael@0: } /* namespace mozilla */ michael@0: michael@0: #endif /* mozilla_TypeTraits_h */