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:
humesikkins 2003-01-31 20:13:57 +00:00
parent 20107644b0
commit 621b2addce
2 changed files with 455 additions and 283 deletions

View file

@ -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

View file

@ -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_