Fixed bugs in TypeTraits' scalar, array, const and volatile detection.
Added Enum- and pointer-to-member-function-detection code. git-svn-id: svn://svn.code.sf.net/p/loki-lib/code/trunk@90 7ec92016-0320-0410-acc4-a06ded1c099a
This commit is contained in:
parent
20107644b0
commit
621b2addce
2 changed files with 455 additions and 283 deletions
|
@ -1,6 +1,6 @@
|
|||
Loki VC 6.0 Port or how to produce C1001 - Internal Compiler Errors
|
||||
-------------------------------------------------------------------
|
||||
Version: 0.3a
|
||||
Version: 0.3b
|
||||
|
||||
Introduction/Compatibility:
|
||||
---------------------------
|
||||
|
@ -30,6 +30,15 @@ If you use Singletons with longevity you must add Singleton.cpp to your project/
|
|||
Fixes:
|
||||
------
|
||||
|
||||
Jan 30, 2003:
|
||||
-------------
|
||||
* In TypeTraits.h: Fixed bugs in TypeTraits' scalar and array detection.
|
||||
const and volatile detection is now based on techniques from boost's type traits
|
||||
(see http://www.boost.org/libs/type_traits/)
|
||||
Added Enum- and pointer-to-member-function-detection code.
|
||||
Thanks to M. Yamada.
|
||||
|
||||
|
||||
Jan 12, 2003:
|
||||
-------------
|
||||
* changed the signature of SmallObject's op new. Now it
|
||||
|
@ -151,8 +160,8 @@ Unfortunately the MSVC 6.0 supports neither of them.
|
|||
E. All template parameters that have a default type of void in the original lib now
|
||||
have int as default type.
|
||||
|
||||
F. In Functor.h I changed a ResultType of type void to VoidAsType (an udt). This change is transparent
|
||||
for the user of Functor.
|
||||
F. In Functor.h I changed a ResultType of type void to VoidAsType (an udt). This change is
|
||||
transparent to the user of Functor.
|
||||
Because I could not think of any general and transparent workaround I followed different
|
||||
strategies. In Visitor.h for example I created new classes (and macros) for the void-case.
|
||||
In other places (for example: MultiMethod.h) this port simply fails to support void as
|
||||
|
@ -240,8 +249,19 @@ Interface changes:
|
|||
|
||||
4. TypeTraits.h
|
||||
|
||||
* Because VC 6.0 lacks partial template specialization, the TypeTraits-Class provides not
|
||||
all the stuff provided by the original library's version.
|
||||
* Because VC 6.0 lacks partial template specialization, the TypeTraits-Class
|
||||
fails to provide the following typedefs:
|
||||
PointeeType, ReferredType, NonVolatileType and UnqualifiedType.
|
||||
|
||||
* Since the VC 6 does not differentiate
|
||||
between void, const void, volatile void and const volatile void the following
|
||||
assertions will fail:
|
||||
assert(TypeTraits<const void>::isConst == 1)
|
||||
assert(TypeTraits<volatile void>::isVolatile == 1)
|
||||
assert(TypeTraits<const volatile void>::isConst == 1)
|
||||
assert(TypeTraits<const volatile void>::isVolatile == 1)
|
||||
|
||||
* This port adds isEnum and isMemberFuncPointer
|
||||
|
||||
|
||||
5. HierarchyGenerator.h
|
||||
|
@ -353,3 +373,4 @@ More info:
|
|||
----------
|
||||
The original Loki library can be found here: http://moderncppdesign.com
|
||||
For Rani Sharoni's VC 7.0 port see: http://www.geocities.com/rani_sharoni/LokiPort.html
|
||||
|
||||
|
|
|
@ -13,15 +13,36 @@
|
|||
// without express or implied warranty.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Last update: Oct 05, 2002
|
||||
// Most of the code is taken from Rani Sharoni's Loki VC 7 port
|
||||
// Reference, pointer and array detection is based on boost's type traits
|
||||
// Last update: Jan 31, 2003
|
||||
// This VC 6 port of TypeTraits is based on Rani Sharoni's Loki VC 7 port.
|
||||
// Reference, pointer, array, const and volatile detection is based on
|
||||
// boost's type traits.
|
||||
// see http://www.boost.org/libs/type_traits/
|
||||
//
|
||||
// The code for Enum- and pointer-to-member-function detection is based on
|
||||
// ideas from M. Yamada - many thanks :)
|
||||
//
|
||||
// AdjReference has moved to namespace-scope. Explicit specialization is
|
||||
// only allowed there.
|
||||
//
|
||||
// known bugs:
|
||||
// assert(TypeTraits<const void>::isConst == 1) fails.
|
||||
// assert(TypeTraits<volatile void>::isVolatile == 1) fails.
|
||||
// assert(TypeTraits<const volatile void>::isConst == 1) fails.
|
||||
// assert(TypeTraits<const volatile void>::isVolatile == 1) fails.
|
||||
// This is because the VC 6 does not differentiate
|
||||
// between void, const void, volatile void and const volatile void.
|
||||
|
||||
#ifndef TYPETRAITS_INC_
|
||||
#define TYPETRAITS_INC_
|
||||
|
||||
//
|
||||
// Ignore forcing value to bool 'true' or 'false' (performance warning)
|
||||
//
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (disable: 4800)
|
||||
#endif
|
||||
|
||||
#include "Typelist.h"
|
||||
|
||||
namespace Loki
|
||||
|
@ -146,13 +167,94 @@ namespace Loki
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
namespace Private
|
||||
{
|
||||
struct pointer_helper
|
||||
template <class T> struct Wrap {};
|
||||
|
||||
// this array-detection approach is based on boost's
|
||||
// Type-Traits. See: boost::array_traits.hpp
|
||||
template <class U>
|
||||
struct ArrayTester
|
||||
{
|
||||
pointer_helper(const volatile void*);
|
||||
private:
|
||||
|
||||
// This function can only be used for non-array-types, because
|
||||
// functions can't return arrays.
|
||||
template<class T>
|
||||
static T(* IsArrayTester1(Wrap<T>) )(Wrap<T>);
|
||||
static char IsArrayTester1(...);
|
||||
|
||||
template<class T>
|
||||
static NO IsArrayTester2(T(*)(Wrap<T>));
|
||||
static YES IsArrayTester2(...);
|
||||
public:
|
||||
enum {
|
||||
value = sizeof(IsArrayTester2(IsArrayTester1(Wrap<U>())))
|
||||
== sizeof(YES)
|
||||
};
|
||||
};
|
||||
|
||||
// const-detection based on boost's
|
||||
// Type-Traits. See: boost\type_traits\is_const.hpp
|
||||
YES IsConstTester(const volatile void*);
|
||||
NO IsConstTester(volatile void *);
|
||||
|
||||
template <bool is_ref, bool array>
|
||||
struct IsConstImpl
|
||||
{
|
||||
template <class T> struct In {enum {value=0};};
|
||||
};
|
||||
template <>
|
||||
struct IsConstImpl<false,false>
|
||||
{
|
||||
template <typename T> struct In
|
||||
{
|
||||
static T* t;
|
||||
enum {value = sizeof(YES) == sizeof(IsConstTester(t))};
|
||||
};
|
||||
};
|
||||
template <>
|
||||
struct IsConstImpl<false,true>
|
||||
{
|
||||
template <typename T> struct In
|
||||
{
|
||||
static T t;
|
||||
enum { value = sizeof(YES) == sizeof(IsConstTester(&t)) };
|
||||
};
|
||||
};
|
||||
|
||||
// this volatile-detection approach is based on boost's
|
||||
// Type-Traits. See: boost\type_traits\is_volatile.hpp
|
||||
YES IsVolatileTester(void const volatile*);
|
||||
NO IsVolatileTester(void const*);
|
||||
|
||||
template <bool is_ref, bool array>
|
||||
struct IsVolatileImpl
|
||||
{
|
||||
template <typename T> struct In
|
||||
{
|
||||
enum {value = 0};
|
||||
};
|
||||
};
|
||||
|
||||
template <>
|
||||
struct IsVolatileImpl<false,false>
|
||||
{
|
||||
template <typename T> struct In
|
||||
{
|
||||
static T* t;
|
||||
enum {value = sizeof(YES) == sizeof(IsVolatileTester(t))};
|
||||
};
|
||||
};
|
||||
|
||||
template <>
|
||||
struct IsVolatileImpl<false,true>
|
||||
{
|
||||
template <typename T> struct In
|
||||
{
|
||||
static T t;
|
||||
enum {value = sizeof(YES) == sizeof(IsVolatileTester(&t))};
|
||||
};
|
||||
};
|
||||
|
||||
struct EnumFalse{ enum {value = 0};};
|
||||
struct EnumTrue{ enum {value = 1};};
|
||||
template<bool IsRef>
|
||||
struct AdjReference
|
||||
{
|
||||
|
@ -166,24 +268,32 @@ namespace Loki
|
|||
template<typename U>
|
||||
struct In { typedef U Result; };
|
||||
};
|
||||
struct PointerHelper
|
||||
{
|
||||
PointerHelper(const volatile void*);
|
||||
};
|
||||
|
||||
|
||||
template <class T>
|
||||
NO EnumDetection(T);
|
||||
|
||||
template <class T>
|
||||
YES EnumDetection(...);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class TypeTraits
|
||||
{
|
||||
|
||||
private:
|
||||
static T MakeT(...);
|
||||
template <class U> struct Wrap{};
|
||||
struct pointer_helper
|
||||
{
|
||||
pointer_helper(const volatile void*);
|
||||
};
|
||||
static Private::YES is_pointer(pointer_helper);
|
||||
static Private::NO is_pointer(...);
|
||||
static Private::YES IsPointer(Private::PointerHelper);
|
||||
static Private::NO IsPointer(...);
|
||||
|
||||
// With the VC 6. Rani Sharoni's approach to detect references unfortunately
|
||||
// results in an error C1001: INTERNER COMPILER- FEHLER
|
||||
// results in an error C1001: INTERNAL COMPILER-ERROR
|
||||
//
|
||||
// this reference-detection approach is based on boost's
|
||||
// Type-Traits. See: boost::composite_traits.h
|
||||
//
|
||||
// is_reference_helper1 is a function taking a Wrap<T> returning
|
||||
// a pointer to a function taking a Wrap<T> returning a T&.
|
||||
|
@ -195,50 +305,33 @@ namespace Loki
|
|||
// In order to detect a reference, use the return-type of is_reference_helper1
|
||||
// with is_reference_helper2.
|
||||
//
|
||||
// this reference-detection approach is based on boost's
|
||||
// Type-Traits. See: boost::composite_traits.h
|
||||
template <class T>
|
||||
static T&(* is_reference_helper1(Wrap<T>) )(Wrap<T>);
|
||||
static Private::NO is_reference_helper1(...);
|
||||
template <class U>
|
||||
static U&(* IsReferenceHelper1(Private::Wrap<U>) )(Private::Wrap<U>);
|
||||
static Private::NO IsReferenceHelper1(...);
|
||||
|
||||
template <class T>
|
||||
static Private::NO is_reference_helper2(T&(*)(Wrap<T>));
|
||||
static Private::YES is_reference_helper2(...);
|
||||
template <class U>
|
||||
static Private::NO IsReferenceHelper2(U&(*)(Private::Wrap<U>));
|
||||
static Private::YES IsReferenceHelper2(...);
|
||||
|
||||
template <class T, class U>
|
||||
static Private::YES is_pointer2member(U T::*);
|
||||
static Private::NO is_pointer2member(...);
|
||||
|
||||
// This function can only be used for non-array-types, because
|
||||
// functions can't return arrays.
|
||||
// this array-detection approach is based on boost's
|
||||
// Type-Traits. See: boost::array_traits.h
|
||||
template <class T>
|
||||
static T(* is_array_helper1(Wrap<T>) )(Wrap<T>);
|
||||
static Private::NO is_array_helper1(...);
|
||||
|
||||
template <class T>
|
||||
static Private::NO is_array_helper2(T(*)(Wrap<T>));
|
||||
static Private::YES is_array_helper2(...);
|
||||
|
||||
template<typename U>
|
||||
static Private::YES is_const(Wrap<const U>);
|
||||
static Private::NO is_const(...);
|
||||
|
||||
template<typename U>
|
||||
static Private::YES is_volatile(Wrap<volatile U>);
|
||||
static Private::NO is_volatile(...);
|
||||
template <class U, class Z>
|
||||
static Private::YES IsPointer2Member(Z U::*);
|
||||
static Private::NO IsPointer2Member(...);
|
||||
struct DummyType{};
|
||||
public:
|
||||
enum {isArray = Private::ArrayTester<T>::value};
|
||||
enum {isReference = sizeof(
|
||||
is_reference_helper2(
|
||||
is_reference_helper1(Wrap<T>()))) == sizeof(Private::YES)};
|
||||
enum {isPointer = sizeof(is_pointer(MakeT())) == sizeof(Private::YES)};
|
||||
enum {isMemberPointer = sizeof(is_pointer2member(MakeT())) == sizeof(Private::YES)};
|
||||
enum {isArray = sizeof(
|
||||
is_array_helper1(
|
||||
is_array_helper2(Wrap<T>()))) == sizeof(Private::YES)};
|
||||
IsReferenceHelper2(
|
||||
IsReferenceHelper1(Private::Wrap<T>()))) == sizeof(Private::YES)};
|
||||
enum {isVoid = Private::IsVoid<T>::value};
|
||||
typedef typename Select<isArray || isVoid,DummyType, T>::Result NewT;
|
||||
|
||||
private:
|
||||
static NewT MakeT();
|
||||
enum {isMemberPointerTemp =
|
||||
sizeof(IsPointer2Member(MakeT())) == sizeof(Private::YES)};
|
||||
public:
|
||||
|
||||
enum {isPointer = sizeof(IsPointer(MakeT())) == sizeof(Private::YES)};
|
||||
enum { isStdUnsignedInt =
|
||||
TL::IndexOf<Private::StdUnsignedInts, T>::value >= 0 };
|
||||
enum { isStdSignedInt =
|
||||
|
@ -256,28 +349,55 @@ namespace Loki
|
|||
enum { isArith = isIntegral || isFloat };
|
||||
enum { isFundamental = isStdFundamental || isArith || isFloat };
|
||||
enum {
|
||||
isConst =
|
||||
sizeof(is_const(Wrap<T>())) == sizeof(Private::YES)
|
||||
isConst = Private::IsConstImpl
|
||||
<isReference, isArray>::template In<T>::value
|
||||
};
|
||||
|
||||
enum {
|
||||
isVolatile =
|
||||
sizeof(is_volatile(Wrap<T>())) == sizeof(Private::YES)
|
||||
isVolatile = Private::IsVolatileImpl
|
||||
<isReference, isArray>::template In<T>::value
|
||||
};
|
||||
enum { isScalar = isStdArith || isPointer || isMemberPointer};
|
||||
private:
|
||||
typedef typename Private::AdjReference<isReference || isVoid>::
|
||||
template In<T>::Result AdjType;
|
||||
|
||||
struct is_scalar
|
||||
{
|
||||
private:
|
||||
struct BoolConvert { BoolConvert(bool); };
|
||||
|
||||
static Private::YES check(BoolConvert);
|
||||
static Private::NO check(...);
|
||||
|
||||
struct NotScalar {};
|
||||
|
||||
typedef typename Select
|
||||
<
|
||||
isVoid || isReference || isArray,
|
||||
NotScalar, T
|
||||
>
|
||||
::Result RetType;
|
||||
|
||||
static RetType get();
|
||||
|
||||
public:
|
||||
|
||||
|
||||
enum { value = sizeof(check(get())) == sizeof(Private::YES) };
|
||||
|
||||
|
||||
}; // is_scalar
|
||||
|
||||
public:
|
||||
|
||||
enum { isScalar = is_scalar::value};
|
||||
typedef typename Select
|
||||
<
|
||||
isScalar || isArray, T, AdjType
|
||||
>
|
||||
::Result ParameterType;
|
||||
|
||||
|
||||
//
|
||||
// We get is_class for free
|
||||
// BUG - fails with functions types (ICE) and unknown size array
|
||||
|
@ -290,13 +410,44 @@ namespace Loki
|
|||
!isReference &&
|
||||
!isVoid
|
||||
};
|
||||
private:
|
||||
typedef typename Loki::Select
|
||||
<
|
||||
isScalar,
|
||||
T,
|
||||
int
|
||||
>::Result MayBeEnum;
|
||||
public:
|
||||
// enum types are the only scalar types that can't be initialized
|
||||
// with 0.
|
||||
// Because we replace all non scalars with int,
|
||||
// template <class T>
|
||||
// YES EnumDetection(...);
|
||||
// will only be selected for enums.
|
||||
enum {
|
||||
isEnum = sizeof(Private::YES) ==
|
||||
sizeof (Private::EnumDetection<MayBeEnum>(0))
|
||||
};
|
||||
|
||||
enum {
|
||||
isMemberFuncPointer = isScalar && !isArith && !isPointer &&
|
||||
!isMemberPointerTemp && !isEnum
|
||||
};
|
||||
enum {isMemberPointer = isMemberPointerTemp || isMemberFuncPointer};
|
||||
};
|
||||
|
||||
}
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (default: 4800)
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Change log:
|
||||
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
|
||||
// May 10, 2002: ported by Rani Sharoni to VC7 (RTM - 9466)
|
||||
// Oct 05, 2002: ported by Benjamin Kaufmann to MSVC 6
|
||||
// Jan 31, 2003: fixed bugs in scalar and array detection.
|
||||
// Added isMemberFuncPointer and isEnum. B.K.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif // TYPETRAITS_INC_
|
Loading…
Add table
Add a link
Reference in a new issue