#pragma once //////////////////////////////////////////////////////////////////////////////// // The Loki Library // Copyright (c) 2001 by Andrei Alexandrescu // This code accompanies the book: // Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design // Patterns Applied". Copyright (c) 2001. Addison-Wesley. // Code covered by the MIT License // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. //////////////////////////////////////////////////////////////////////////////// namespace tp { template struct TypeSelect { typedef T Result; }; template struct TypeSelect { typedef U Result; }; } namespace tp { //////////////////////////////////////////////////////////////////////////////// // class template IsSameType // Return true iff two given types are the same // Invocation: SameType::value // where: // T and U are types // Result evaluates to true iff U == T (types equal) //////////////////////////////////////////////////////////////////////////////// template struct IsSameType { enum { value = false }; }; template struct IsSameType { enum { value = true }; }; //////////////////////////////////////////////////////////////////////////////// // Helper types Small and Big - guarantee that sizeof(Small) < sizeof(Big) //////////////////////////////////////////////////////////////////////////////// namespace Private { template struct ConversionHelper { typedef char Small; struct Big { char dummy[2]; }; static Big Test(...); static Small Test(U); static T MakeT(); }; } //////////////////////////////////////////////////////////////////////////////// // class template Conversion // Figures out the conversion relationships between two types // Invocations (T and U are types): // a) Conversion::exists // returns (at compile time) true if there is an implicit conversion from T // to U (example: Derived to Base) // b) Conversion::exists2Way // returns (at compile time) true if there are both conversions from T // to U and from U to T (example: int to char and back) // c) Conversion::sameType // returns (at compile time) true if T and U represent the same type // // Caveat: might not work if T and U are in a private inheritance hierarchy. //////////////////////////////////////////////////////////////////////////////// template struct Conversion { typedef Private::ConversionHelper H; #ifndef __MWERKS__ enum { exists = sizeof(typename H::Small) == sizeof((H::Test(H::MakeT()))) }; #else enum { exists = false }; #endif enum { exists2Way = exists && Conversion::exists }; enum { sameType = false }; }; template struct Conversion { enum { exists = 1, exists2Way = 1, sameType = 1 }; }; template struct Conversion { enum { exists = 0, exists2Way = 0, sameType = 0 }; }; template struct Conversion { enum { exists = 0, exists2Way = 0, sameType = 0 }; }; template <> struct Conversion { public: enum { exists = 1, exists2Way = 1, sameType = 1 }; }; //////////////////////////////////////////////////////////////////////////////// // class template SuperSubclass // Invocation: SuperSubclass::value where B and D are types. // Returns true if B is a public base of D, or if B and D are aliases of the // same type. // // Caveat: might not work if T and U are in a private inheritance hierarchy. //////////////////////////////////////////////////////////////////////////////// template struct SuperSubclass { enum { value = (::tp::Conversion::exists && !::tp::Conversion::sameType) }; // Dummy enum to make sure that both classes are fully defined. enum { dontUseWithIncompleteTypes = (sizeof(T) == sizeof(U)) }; }; template <> struct SuperSubclass { enum { value = false }; }; template struct SuperSubclass { enum { value = (::tp::Conversion::exists && !::tp::Conversion::sameType) }; // Dummy enum to make sure that both classes are fully defined. enum { dontUseWithIncompleteTypes = (0 == sizeof(U)) }; }; template struct SuperSubclass { enum { value = (::tp::Conversion::exists && !::tp::Conversion::sameType) }; // Dummy enum to make sure that both classes are fully defined. enum { dontUseWithIncompleteTypes = (sizeof(T) == 0) }; }; //////////////////////////////////////////////////////////////////////////////// // class template SuperSubclassStrict // Invocation: SuperSubclassStrict::value where B and D are types. // Returns true if B is a public base of D. // // Caveat: might not work if T and U are in a private inheritance hierarchy. //////////////////////////////////////////////////////////////////////////////// template struct SuperSubclassStrict { enum { value = (::tp::Conversion::exists && !::tp::Conversion::sameType && !::tp::Conversion::sameType) }; // Dummy enum to make sure that both classes are fully defined. enum { dontUseWithIncompleteTypes = (sizeof(T) == sizeof(U)) }; }; template<> struct SuperSubclassStrict { enum { value = false }; }; template struct SuperSubclassStrict { enum { value = (::tp::Conversion::exists && !::tp::Conversion::sameType && !::tp::Conversion::sameType) }; // Dummy enum to make sure that both classes are fully defined. enum { dontUseWithIncompleteTypes = (0 == sizeof(U)) }; }; template struct SuperSubclassStrict { enum { value = (::tp::Conversion::exists && !::tp::Conversion::sameType && !::tp::Conversion::sameType) }; // Dummy enum to make sure that both classes are fully defined. enum { dontUseWithIncompleteTypes = (sizeof(T) == 0) }; }; } // namespace tp //////////////////////////////////////////////////////////////////////////////// // macro SUPERSUBCLASS // Invocation: SUPERSUBCLASS(B, D) where B and D are types. // Returns true if B is a public base of D, or if B and D are aliases of the // same type. // // Caveat: might not work if T and U are in a private inheritance hierarchy. // Deprecated: Use SuperSubclass class template instead. //////////////////////////////////////////////////////////////////////////////// #define SUPERSUBCLASS(T, U) ::tp::SuperSubclass::value //////////////////////////////////////////////////////////////////////////////// // macro SUPERSUBCLASS_STRICT // Invocation: SUPERSUBCLASS(B, D) where B and D are types. // Returns true if B is a public base of D. // // Caveat: might not work if T and U are in a private inheritance hierarchy. // Deprecated: Use SuperSubclassStrict class template instead. //////////////////////////////////////////////////////////////////////////////// #define SUPERSUBCLASS_STRICT(T, U) ::tp::SuperSubclassStrict::value namespace tp { struct NullType {}; //////////////////////////////////////////////////////////////////////////////// // class template Typelist // The building block of typelists of any length // Use it through the LOKI_TYPELIST_NN macros // Defines nested types: // Head (first element, a non-typelist type by convention) // Tail (second element, can be another typelist) //////////////////////////////////////////////////////////////////////////////// template struct Typelist { typedef T Head; typedef U Tail; }; // Typelist utility algorithms namespace TL { //////////////////////////////////////////////////////////////////////////////// // class template MakeTypelist // Takes a number of arguments equal to its numeric suffix // The arguments are type names. // MakeTypelist::Result // returns a typelist that is of T1, T2, ... //////////////////////////////////////////////////////////////////////////////// template < typename T1 = NullType, typename T2 = NullType, typename T3 = NullType, typename T4 = NullType, typename T5 = NullType, typename T6 = NullType, typename T7 = NullType, typename T8 = NullType, typename T9 = NullType, typename T10 = NullType, typename T11 = NullType, typename T12 = NullType, typename T13 = NullType, typename T14 = NullType, typename T15 = NullType, typename T16 = NullType, typename T17 = NullType, typename T18 = NullType > struct MakeTypelist { private: typedef typename MakeTypelist < T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18 > ::Result TailResult; public: typedef Typelist Result; }; template<> struct MakeTypelist<> { typedef NullType Result; }; //////////////////////////////////////////////////////////////////////////////// // class template Length // Computes the length of a typelist // Invocation (TList is a typelist): // Length::value // returns a compile-time constant containing the length of TList, not counting // the end terminator (which by convention is NullType) //////////////////////////////////////////////////////////////////////////////// template struct Length; template <> struct Length { enum { value = 0 }; }; template struct Length< Typelist > { enum { value = 1 + Length::value }; }; //////////////////////////////////////////////////////////////////////////////// // class template TypeAt // Finds the type at a given index in a typelist // Invocation (TList is a typelist and index is a compile-time integral // constant): // TypeAt::Result // returns the type in position 'index' in TList // If you pass an out-of-bounds index, the result is a compile-time error //////////////////////////////////////////////////////////////////////////////// template struct TypeAt; template struct TypeAt, 0> { typedef Head Result; }; template struct TypeAt, i> { typedef typename TypeAt::Result Result; }; //////////////////////////////////////////////////////////////////////////////// // class template TypeAtNonStrict // Finds the type at a given index in a typelist // Invocations (TList is a typelist and index is a compile-time integral // constant): // a) TypeAt::Result // returns the type in position 'index' in TList, or NullType if index is // out-of-bounds // b) TypeAt::Result // returns the type in position 'index' in TList, or D if index is out-of-bounds //////////////////////////////////////////////////////////////////////////////// template struct TypeAtNonStrict { typedef DefaultType Result; }; template struct TypeAtNonStrict, 0, DefaultType> { typedef Head Result; }; template struct TypeAtNonStrict, i, DefaultType> { typedef typename TypeAtNonStrict::Result Result; }; //////////////////////////////////////////////////////////////////////////////// // class template IndexOf // Finds the index of a type in a typelist // Invocation (TList is a typelist and T is a type): // IndexOf::value // returns the position of T in TList, or NullType if T is not found in TList //////////////////////////////////////////////////////////////////////////////// template struct IndexOf; template struct IndexOf { enum { value = -1 }; }; template struct IndexOf, T> { enum { value = 0 }; }; template struct IndexOf, T> { private: enum { temp = IndexOf::value }; public: enum { value = (temp == -1 ? -1 : 1 + temp) }; }; //////////////////////////////////////////////////////////////////////////////// // class template Append // Appends a type or a typelist to another // Invocation (TList is a typelist and T is either a type or a typelist): // Append::Result // returns a typelist that is TList followed by T and NullType-terminated //////////////////////////////////////////////////////////////////////////////// template struct Append; template <> struct Append { typedef NullType Result; }; template struct Append { typedef Typelist Result; }; template struct Append > { typedef Typelist Result; }; template struct Append, T> { typedef Typelist::Result> Result; }; //////////////////////////////////////////////////////////////////////////////// // class template Erase // Erases the first occurence, if any, of a type in a typelist // Invocation (TList is a typelist and T is a type): // Erase::Result // returns a typelist that is TList without the first occurence of T //////////////////////////////////////////////////////////////////////////////// template struct Erase; template // Specialization 1 struct Erase { typedef NullType Result; }; template // Specialization 2 struct Erase, T> { typedef Tail Result; }; template // Specialization 3 struct Erase, T> { typedef Typelist::Result> Result; }; //////////////////////////////////////////////////////////////////////////////// // class template EraseAll // Erases all first occurences, if any, of a type in a typelist // Invocation (TList is a typelist and T is a type): // EraseAll::Result // returns a typelist that is TList without any occurence of T //////////////////////////////////////////////////////////////////////////////// template struct EraseAll; template struct EraseAll { typedef NullType Result; }; template struct EraseAll, T> { // Go all the way down the list removing the type typedef typename EraseAll::Result Result; }; template struct EraseAll, T> { // Go all the way down the list removing the type typedef Typelist::Result> Result; }; //////////////////////////////////////////////////////////////////////////////// // class template NoDuplicates // Removes all duplicate types in a typelist // Invocation (TList is a typelist): // NoDuplicates::Result //////////////////////////////////////////////////////////////////////////////// template struct NoDuplicates; template <> struct NoDuplicates { typedef NullType Result; }; template struct NoDuplicates< Typelist > { private: typedef typename NoDuplicates::Result L1; typedef typename Erase::Result L2; public: typedef Typelist Result; }; //////////////////////////////////////////////////////////////////////////////// // class template Replace // Replaces the first occurence of a type in a typelist, with another type // Invocation (TList is a typelist, T, U are types): // Replace::Result // returns a typelist in which the first occurence of T is replaced with U //////////////////////////////////////////////////////////////////////////////// template struct Replace; template struct Replace { typedef NullType Result; }; template struct Replace, T, U> { typedef Typelist Result; }; template struct Replace, T, U> { typedef Typelist::Result> Result; }; //////////////////////////////////////////////////////////////////////////////// // class template ReplaceAll // Replaces all occurences of a type in a typelist, with another type // Invocation (TList is a typelist, T, U are types): // Replace::Result // returns a typelist in which all occurences of T is replaced with U //////////////////////////////////////////////////////////////////////////////// template struct ReplaceAll; template struct ReplaceAll { typedef NullType Result; }; template struct ReplaceAll, T, U> { typedef Typelist::Result> Result; }; template struct ReplaceAll, T, U> { typedef Typelist::Result> Result; }; //////////////////////////////////////////////////////////////////////////////// // class template Reverse // Reverses a typelist // Invocation (TList is a typelist): // Reverse::Result // returns a typelist that is TList reversed //////////////////////////////////////////////////////////////////////////////// template struct Reverse; template <> struct Reverse { typedef NullType Result; }; template struct Reverse< Typelist > { typedef typename Append< typename Reverse::Result, Head>::Result Result; }; //////////////////////////////////////////////////////////////////////////////// // class template MostDerived // Finds the type in a typelist that is the most derived from a given type // Invocation (TList is a typelist, T is a type): // MostDerived::Result // returns the type in TList that's the most derived from T //////////////////////////////////////////////////////////////////////////////// template struct MostDerived; template struct MostDerived { typedef T Result; }; template struct MostDerived, T> { private: typedef typename MostDerived::Result Candidate; public: typedef typename TypeSelect< SuperSubclass::value, Head, Candidate>::Result Result; }; //////////////////////////////////////////////////////////////////////////////// // class template DerivedToFront // Arranges the types in a typelist so that the most derived types appear first // Invocation (TList is a typelist): // DerivedToFront::Result // returns the reordered TList //////////////////////////////////////////////////////////////////////////////// template struct DerivedToFront; template <> struct DerivedToFront { typedef NullType Result; }; template struct DerivedToFront< Typelist > { private: typedef typename MostDerived::Result TheMostDerived; typedef typename Replace::Result Temp; typedef typename DerivedToFront::Result L; public: typedef Typelist Result; }; } // namespace TL template < class T01 = NullType, class T02 = NullType, class T03 = NullType, class T04 = NullType, class T05 = NullType, class T06 = NullType, class T07 = NullType, class T08 = NullType, class T09 = NullType, class T10 = NullType, class T11 = NullType, class T12 = NullType, class T13 = NullType, class T14 = NullType, class T15 = NullType, class T16 = NullType, class T17 = NullType, class T18 = NullType, class T19 = NullType, class T20 = NullType > class Seq { typedef typename Seq< T02, T03, T04, T05, T06, T07, T08, T09, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20>::list TailResult; public: typedef Typelist list; }; template<> struct Seq<> { typedef NullType list; }; } // namespace tp #if 0 #define TYPELIST1(T1) ::compiler::Typelist #define TYPELIST2(T1, T2) ::compiler::Typelist #define TYPELIST3(T1, T2, T3) ::compiler::Typelist #define TYPELIST4(T1, T2, T3, T4) ::compiler::Typelist #define TYPELIST5(T1, T2, T3, T4, T5) ::compiler::Typelist #define TYPELIST6(T1, T2, T3, T4, T5, T6) ::compiler::Typelist #define TYPELIST7(T1, T2, T3, T4, T5, T6, T7) ::compiler::Typelist #define TYPELIST8(T1, T2, T3, T4, T5, T6, T7, T8) ::compiler::Typelist #define TYPELIST9(T1, T2, T3, T4, T5, T6, T7, T8, T9) ::compiler::Typelist #define TYPELIST10(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) ::compiler::Typelist #endif #include #ifdef _MSC_VER #pragma warning( push ) #pragma warning( disable : 4180 ) //qualifier applied to function type has no meaning; ignored #endif namespace tp { //////////////////////////////////////////////////////////////////////////////// // class template IsCustomUnsignedInt // Offers a means to integrate nonstandard built-in unsigned integral types // (such as unsigned __int64 or unsigned long long int) with the TypeTraits // class template defined below. // Invocation: IsCustomUnsignedInt where T is any type // Defines 'value', an enum that is 1 iff T is a custom built-in unsigned // integral type // Specialize this class template for nonstandard unsigned integral types // and define value = 1 in those specializations //////////////////////////////////////////////////////////////////////////////// template struct IsCustomUnsignedInt { enum { value = 0 }; }; //////////////////////////////////////////////////////////////////////////////// // class template IsCustomSignedInt // Offers a means to integrate nonstandard built-in unsigned integral types // (such as unsigned __int64 or unsigned long long int) with the TypeTraits // class template defined below. // Invocation: IsCustomSignedInt where T is any type // Defines 'value', an enum that is 1 iff T is a custom built-in signed // integral type // Specialize this class template for nonstandard unsigned integral types // and define value = 1 in those specializations //////////////////////////////////////////////////////////////////////////////// template struct IsCustomSignedInt { enum { value = 0 }; }; //////////////////////////////////////////////////////////////////////////////// // class template IsCustomFloat // Offers a means to integrate nonstandard floating point types with the // TypeTraits class template defined below. // Invocation: IsCustomFloat where T is any type // Defines 'value', an enum that is 1 iff T is a custom built-in // floating point type // Specialize this class template for nonstandard unsigned integral types // and define value = 1 in those specializations //////////////////////////////////////////////////////////////////////////////// template struct IsCustomFloat { enum { value = 0 }; }; //////////////////////////////////////////////////////////////////////////////// // Helper types for class template TypeTraits defined below //////////////////////////////////////////////////////////////////////////////// namespace Private { typedef Seq::list StdUnsignedInts; typedef Seq::list StdSignedInts; typedef Seq::list StdOtherInts; typedef Seq::list StdFloats; template struct AddPointer { typedef U* Result; }; template struct AddPointer { typedef U* Result; }; template struct AddReference { typedef U& Result; }; template struct AddReference { typedef U& Result; }; template <> struct AddReference { typedef NullType Result; }; template struct AddParameterType { typedef const U& Result; }; template struct AddParameterType { typedef U& Result; }; template <> struct AddParameterType { typedef NullType Result; }; }// namespace Private //////////////////////////////////////////////////////////////////////////////// // class template TypeTraits // // Figures out at compile time various properties of any given type // Invocations (T is a type, TypeTraits::Property): // // - isPointer : returns true if T is a pointer type // - PointeeType : returns the type to which T points if T is a pointer // type, NullType otherwise // - isReference : returns true if T is a reference type // - ReferredType : returns the type to which T refers if T is a reference // type, NullType otherwise // - isMemberPointer : returns true if T is a pointer to member type // - isStdUnsignedInt: returns true if T is a standard unsigned integral type // - isStdSignedInt : returns true if T is a standard signed integral type // - isStdIntegral : returns true if T is a standard integral type // - isStdFloat : returns true if T is a standard floating-point type // - isStdArith : returns true if T is a standard arithmetic type // - isStdFundamental: returns true if T is a standard fundamental type // - isUnsignedInt : returns true if T is a unsigned integral type // - isSignedInt : returns true if T is a signed integral type // - isIntegral : returns true if T is a integral type // - isFloat : returns true if T is a floating-point type // - isArith : returns true if T is a arithmetic type // - isFundamental : returns true if T is a fundamental type // - ParameterType : returns the optimal type to be used as a parameter for // functions that take Ts // - isConst : returns true if T is a const-qualified type // - NonConstType : Type with removed 'const' qualifier from T, if any // - isVolatile : returns true if T is a volatile-qualified type // - NonVolatileType : Type with removed 'volatile' qualifier from T, if any // - UnqualifiedType : Type with removed 'const' and 'volatile' qualifiers from // T, if any // - ParameterType : returns the optimal type to be used as a parameter // for functions that take 'const T's // //////////////////////////////////////////////////////////////////////////////// template class TypeTraits { private: template struct ReferenceTraits { enum { result = false }; typedef U ReferredType; }; template struct ReferenceTraits { enum { result = true }; typedef U ReferredType; }; template struct PointerTraits { enum { result = false }; typedef NullType PointeeType; }; template struct PointerTraits { enum { result = true }; typedef U PointeeType; }; template struct PointerTraits { enum { result = true }; typedef U PointeeType; }; template struct PToMTraits { enum { result = false }; }; template struct PToMTraits { enum { result = true }; }; template struct PToMTraits { enum { result = true }; }; template struct UnConst { typedef U Result; enum { isConst = 0 }; }; template struct UnConst { typedef U Result; enum { isConst = 1 }; }; template struct UnConst { typedef U& Result; enum { isConst = 1 }; }; template struct UnVolatile { typedef U Result; enum { isVolatile = 0 }; }; template struct UnVolatile { typedef U Result; enum { isVolatile = 1 }; }; template struct UnVolatile { typedef U& Result; enum { isVolatile = 1 }; }; public: typedef typename UnConst::Result NonConstType; typedef typename UnVolatile::Result NonVolatileType; typedef typename UnVolatile::Result>::Result UnqualifiedType; typedef typename PointerTraits::PointeeType PointeeType; typedef typename ReferenceTraits::ReferredType ReferredType; enum { isConst = UnConst::isConst }; enum { isVolatile = UnVolatile::isVolatile }; enum { isReference = ReferenceTraits::result }; enum { isMemberPointer = PToMTraits::ReferredType >::result }; enum { isPointer = PointerTraits::ReferredType >::result }; enum { isStdUnsignedInt = TL::IndexOf::value >= 0 || TL::IndexOf::ReferredType>::value >= 0 }; enum { isStdSignedInt = TL::IndexOf::value >= 0 || TL::IndexOf::ReferredType>::value >= 0 }; enum { isStdIntegral = isStdUnsignedInt || isStdSignedInt || TL::IndexOf::value >= 0 || TL::IndexOf::ReferredType>::value >= 0 }; enum { isStdFloat = TL::IndexOf::value >= 0 || TL::IndexOf::ReferredType>::value >= 0 }; enum { isStdArith = isStdIntegral || isStdFloat }; enum { isStdFundamental = isStdArith || isStdFloat || Conversion::sameType }; enum { isUnsignedInt = isStdUnsignedInt || IsCustomUnsignedInt::value }; enum { isSignedInt = isStdSignedInt || IsCustomSignedInt::value }; enum { isIntegral = isStdIntegral || isUnsignedInt || isSignedInt }; enum { isFloat = isStdFloat || IsCustomFloat::value }; enum { isArith = isIntegral || isFloat }; enum { isFundamental = isStdFundamental || isArith }; typedef typename TypeSelect::Result>::Result ParameterType; }; } #ifdef _MSC_VER #pragma warning( pop ) #endif // _MSC_VER