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,35 +30,44 @@ If you use Singletons with longevity you must add Singleton.cpp to your project/
Fixes:
------
Jan 12, 2003:
-------------
* changed the signature of SmallObject's op new. Now it
matches the corresponding op delete.
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
matches the corresponding op delete.
Thanks to M.Yamada for the hint and the solution.
Dec 08, 2002:
-------------
* In HierarchyGenerators.h: Sergey Khachatrian reported a bug
in GenScatterHierarchy when used with a typelist containing
equal types (e.g. GenScatterHierarchy<TYPELIST_2(int, int), UnitWrapper>
resp. Tuple<TYPELIST_2(int, int)>)
Fixing the bug I found another MSVC6-Problem in the Field-function.
The workaround for this problems results in an interface change.
Dec 08, 2002:
-------------
* In HierarchyGenerators.h: Sergey Khachatrian reported a bug
in GenScatterHierarchy when used with a typelist containing
equal types (e.g. GenScatterHierarchy<TYPELIST_2(int, int), UnitWrapper>
resp. Tuple<TYPELIST_2(int, int)>)
Fixing the bug I found another MSVC6-Problem in the Field-function.
The workaround for this problems results in an interface change.
please refer to the section "Interface changes" below for further information.
please refer to the section "Interface changes" below for further information.
Dec 03, 2002
-------------
* In MSVC6Helpers.h: The original version failed to qualify some types from the
Private-Namespace.
Thanks to Adi Shavit for pointing that out
Dec 03, 2002
-------------
* In MSVC6Helpers.h: The original version failed to qualify some types from the
Private-Namespace.
Thanks to Adi Shavit for pointing that out
* In Threads.h: Changed wrong ctor/dtor names in ObjectLevelLockable.
Thanks to Adi Shavit for pointing that out
* In Threads.h: Changed wrong ctor/dtor names in ObjectLevelLockable.
Thanks to Adi Shavit for pointing that out
Nov 19, 2002:
-------------
* In SmartPtr.h: Changed template ctors. See Notes.
Nov 19, 2002:
-------------
* In SmartPtr.h: Changed template ctors. See Notes.
Notes:
------
@ -73,90 +82,90 @@ F. return statements with an expression of type cv in functions with a return ty
Unfortunately the MSVC 6.0 supports neither of them.
A. I used various techniques to simulate partial template specialization. In some cases
these techniques allowed me to retain the original interfaces but often that was not
possible (or better: i did not find a proper solution). In any case it leads
to increasing code complexity :-)
A. I used various techniques to simulate partial template specialization. In some cases
these techniques allowed me to retain the original interfaces but often that was not
possible (or better: i did not find a proper solution). In any case it leads
to increasing code complexity :-)
B. One way to simulate template template parameters is to replace the template class with
a normal class containing a nested template class. You then move the original functionality
to the nested class.
The problem with this approach is MSVC's 'dependent template typedef bug'. MSVC 6.0 does not
allow something like this:
B. One way to simulate template template parameters is to replace the template class with
a normal class containing a nested template class. You then move the original functionality
to the nested class.
The problem with this approach is MSVC's 'dependent template typedef bug'. MSVC 6.0 does not
allow something like this:
[code]
template <class APolicy, class T>
struct Foo
{
// 'error C1001 - Internal Compiler Error' here
typedef typename APolicy::template In<T> type;
};
[code]
template <class APolicy, class T>
struct Foo
{
// 'error C1001 - Internal Compiler Error' here
typedef typename APolicy::template In<T> type;
};
[/code]
[/code]
To make a long story short, I finally decided to use boost::mpl's apply-technique to
simulate template template parameters. This approach works fine with MSVC 6.0. But be warned,
this technique uses not valid C++.
Of course, replacing template template parameters always results in some interface changes.
To make a long story short, I finally decided to use boost::mpl's apply-technique to
simulate template template parameters. This approach works fine with MSVC 6.0. But be warned,
this technique uses not valid C++.
Of course, replacing template template parameters always results in some interface changes.
C. I added dummy-Parameters to (Member-)Functions that depend on explicit template
argument specification. These dummy-Parameters help the compiler in deducing the template
parameters that otherwise need to be explicitly specified.
Example:
[code]
struct Foo
{
template <class T>
T Func();
};
[/code]
becomes
[code]
struct Foo
{
template <class T>
T Func(T* pDummy1);
};
[/code]
in this port.
C. I added dummy-Parameters to (Member-)Functions that depend on explicit template
argument specification. These dummy-Parameters help the compiler in deducing the template
parameters that otherwise need to be explicitly specified.
Example:
[code]
struct Foo
{
template <class T>
T Func();
};
[/code]
becomes
[code]
struct Foo
{
template <class T>
T Func(T* pDummy1);
};
[/code]
in this port.
Update:
-------
The MSVC 6.0 sometimes does not overload normal functions depending
on explicit argument specification correctly (see: Microsoft KB Article - 240871)
The following code demonstrates the problem:
[code]
template <unsigned i, class T>
void BugDemonstration(T p)
{
printf("BugDemonstration called with i = %d\n", i);
}
Update:
-------
The MSVC 6.0 sometimes does not overload normal functions depending
on explicit argument specification correctly (see: Microsoft KB Article - 240871)
The following code demonstrates the problem:
[code]
template <unsigned i, class T>
void BugDemonstration(T p)
{
printf("BugDemonstration called with i = %d\n", i);
}
int main()
{
GenScatterHierarchy<TYPELIST_3(int, int, int), TestUnitWrapper> Bla;
// will always print: "BugDemonstration called with i = 2";
BugDemonstration<0>(Bla);
BugDemonstration<1>(Bla);
BugDemonstration<2>(Bla);
}
[/code]
int main()
{
GenScatterHierarchy<TYPELIST_3(int, int, int), TestUnitWrapper> Bla;
// will always print: "BugDemonstration called with i = 2";
BugDemonstration<0>(Bla);
BugDemonstration<1>(Bla);
BugDemonstration<2>(Bla);
}
[/code]
As a workaround i added dummy-parameters.
As a workaround i added dummy-parameters.
D. Virtual functions that use covariant return types (e.g. return a pointer to Derived)
in the original library were changed so that they have exactly the
same return type as the original virtual function (e.g. return a pointer to Base).
D. Virtual functions that use covariant return types (e.g. return a pointer to Derived)
in the original library were changed so that they have exactly the
same return type as the original virtual function (e.g. return a pointer to Base).
E. All template parameters that have a default type of void in the original lib now
have int as default type.
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.
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
return type :-(
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
return type :-(
Some words to template-ctors resp. template assignment operators:
The MSVC 6.0 introduces an order-dependency for template ctor
@ -168,11 +177,11 @@ So instead of
template <class T>
struct Foo
{
Foo(const Foo&)
{}
template <class U>
Foo(const Foo<U>& r)
{}
Foo(const Foo&)
{}
template <class U>
Foo(const Foo<U>& r)
{}
};
[/code]
you *need* to write:
@ -180,12 +189,12 @@ you *need* to write:
template <class T>
struct Foo
{
template <class U>
Foo(const Foo<U>& r)
{}
template <class U>
Foo(const Foo<U>& r)
{}
Foo(const Foo& r)
{}
Foo(const Foo& r)
{}
};
[/code]
@ -198,12 +207,12 @@ the form of a copy-ctor. If you write something like this (as in the functor-cla
template <class T>
struct Foo
{
template <class Fun>
Foo(Fun r)
{}
template <class Fun>
Foo(Fun r)
{}
Foo(const Foo& r)
{}
Foo(const Foo& r)
{}
};
[/code]
then the VC will no longer find a copy-ctor.
@ -214,111 +223,122 @@ Interface changes:
------------------
1. In Threads.h:
* Thread-Policies changed from class templates to normal classes containing a
nested class template 'In'.
* Thread-Policies changed from class templates to normal classes containing a
nested class template 'In'.
consequences:
This change is not very dramatic because it won't break code using this port when
switching to the original library (only new Thread-Policies must be changed)
consequences:
This change is not very dramatic because it won't break code using this port when
switching to the original library (only new Thread-Policies must be changed)
2. In Singleton.h:
* The Creation- and Lifetime-Policies are no longer class templates. Instead they all use
Member-Templates.
* The Creation- and Lifetime-Policies are no longer class templates. Instead they all use
Member-Templates.
consequences:
Again this change will only break new Policies when switching to the
original library.
consequences:
Again this change will only break new Policies when switching to the
original library.
3. In Functor.h:
* No covariant return types.
* No covariant return types.
consequences:
DoClone always returns a FunctorImplBase<R, ThreadingModel>* where R is the functor's return
type and ThreadingModel its current ThreadingModel.
consequences:
DoClone always returns a FunctorImplBase<R, ThreadingModel>* where R is the functor's return
type and ThreadingModel its current ThreadingModel.
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
* I used Mat Marcus' approach to port GenScatterHierarchy.
See http://lists.boost.org/MailArchives/boost/msg20915.php) for the consequences.
* I used Mat Marcus' approach to port GenScatterHierarchy.
See http://lists.boost.org/MailArchives/boost/msg20915.php) for the consequences.
* Same for GenLinearHierarchy
* Same for GenLinearHierarchy
* Unit is no longer a template template parameter.
* Unit is no longer a template template parameter.
consequences:
For every concrete unit-template there must be a normal class containing
a nested-template class called 'In'. 'In' should only contain a typedef to the
concrete Unit.
consequences:
For every concrete unit-template there must be a normal class containing
a nested-template class called 'In'. 'In' should only contain a typedef to the
concrete Unit.
Update:
The port's original version of GenScatterHierarchy does not work when used
with typelists containing equal types.
The problem is due to a VC bug. The VC fails to compile code similar
to this, although it is perfectly legal.
[code]
template <class T>
class Wrapper
{};
Update:
The port's original version of GenScatterHierarchy does not work when used
with typelists containing equal types.
The problem is due to a VC bug. The VC fails to compile code similar
to this, although it is perfectly legal.
[code]
template <class T>
class Wrapper
{};
template <class T>
struct B : public Wrapper<T>
{};
template <class T>
struct B : public Wrapper<T>
{};
// ERROR: 'A<T>' : direct base 'Wrapper<T>' is inaccessible; already a base of 'B<T>'
template <class T>
class A : public B<T>, public Wrapper<T>
{};
[/code]
// ERROR: 'A<T>' : direct base 'Wrapper<T>' is inaccessible; already a base of 'B<T>'
template <class T>
class A : public B<T>, public Wrapper<T>
{};
[/code]
Unfortunately my workaround has a big drawback.
GenScatterHierarchy now has to generate a lot more classes.
Alexandrescu's original implementation generates 3*n classes (n - number of types in the typelist)
The old version of my port creates 4 * n + 1
The new version will create 5 * n
Unfortunately my workaround has a big drawback.
GenScatterHierarchy now has to generate a lot more classes.
Alexandrescu's original implementation generates 3*n classes (n - number of types in the typelist)
The old version of my port creates 4 * n + 1
The new version will create 5 * n
The fix also reveals the "Explicitly Specified Template Functions Not Overloaded Correctly"-Bug
(Microsoft KB Article - 240871) in the Field-Function taking a nontype int Parameter.
The fix also reveals the "Explicitly Specified Template Functions Not Overloaded Correctly"-Bug
(Microsoft KB Article - 240871) in the Field-Function taking a nontype int Parameter.
This leads to an interface change:
Instead of: Field<0>(obj)
one now has to write
Field(obj, Int2Type<0>());
This leads to an interface change:
Instead of: Field<0>(obj)
one now has to write
Field(obj, Int2Type<0>());
I added a macro FIELD. Using this macro one can write
FIELD(obj, 0)
I added a macro FIELD. Using this macro one can write
FIELD(obj, 0)
6. Factory.h
* The Error-Policy for Factory and CloneFactory is no longer a template template parameter.
Use a class with member-templates instead.
* The Error-Policy for Factory and CloneFactory is no longer a template template parameter.
Use a class with member-templates instead.
consequences:
This change will only break new Policies when switching to the
original library.
consequences:
This change will only break new Policies when switching to the
original library.
7. AbstractFactory.h
* no covariant return types
* no covariant return types
* no template template parameters
For every concrete Factory-Unit there must be a normal class containing
a nested-template class called 'In'. 'In' shall contain a typedef to the
concrete Factory-Unit.
* no template template parameters
For every concrete Factory-Unit there must be a normal class containing
a nested-template class called 'In'. 'In' shall contain a typedef to the
concrete Factory-Unit.
* Added a dummy-Parameter to AbstractFactory::Create (see C.)
Calling syntax changed from:
ConcProduct* p = aFactory.Create<ConcProduct>();
to
ConcProduct* p = aFactory.Create((ConcProduct*)0);
* Added a dummy-Parameter to AbstractFactory::Create (see C.)
Calling syntax changed from:
ConcProduct* p = aFactory.Create<ConcProduct>();
to
ConcProduct* p = aFactory.Create((ConcProduct*)0);
8. SmartPtr.h
@ -330,26 +350,27 @@ Interface changes:
9. Visitor.h
* no template template parameters
(see 7.for a description of the consequences)
* no template template parameters
(see 7.for a description of the consequences)
* This port fails to correctly support void return types. As a workaround it provides
a set of complete new classes (and macros) for void. Default arguments of type void
were replaced by arguments of type int.
* This port fails to correctly support void return types. As a workaround it provides
a set of complete new classes (and macros) for void. Default arguments of type void
were replaced by arguments of type int.
10. MultiMethods.h
* replaced all template template parameters with 'normal' parameters (see 7.
for a description of the consequences)
* replaced all template template parameters with 'normal' parameters (see 7.
for a description of the consequences)
* This port does not support functions with return type void.
* This port does not support functions with return type void.
* dummy parameters were added to functions that otherwise would depend on
explicit template argument specification (14.8.1).
* dummy parameters were added to functions that otherwise would depend on
explicit template argument specification (14.8.1).
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

@ -2,26 +2,47 @@
// The Loki Library
// Copyright (c) 2001 by Andrei Alexandrescu
// This code accompanies the book:
// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design
// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design
// Patterns Applied". Copyright (c) 2001. Addison-Wesley.
// Permission to use, copy, modify, distribute and sell this software for any
// purpose is hereby granted without fee, provided that the above copyright
// notice appear in all copies and that both that copyright notice and this
// Permission to use, copy, modify, distribute and sell this software for any
// purpose is hereby granted without fee, provided that the above copyright
// notice appear in all copies and that both that copyright notice and this
// permission notice appear in supporting documentation.
// The author or Addison-Welsey Longman make no representations about the
// suitability of this software for any purpose. It is provided "as is"
// The author or Addison-Welsey Longman make no representations about the
// suitability of this software for any purpose. It is provided "as is"
// 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
@ -29,7 +50,7 @@ namespace Loki
////////////////////////////////////////////////////////////////////////////////
// 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
// (such as unsigned __int64 or unsigned long long int) with the TypeTraits
// class template defined below.
// Invocation: IsCustomUnsignedInt<T> where T is any type
// Defines 'value', an enum that is 1 iff T is a custom built-in unsigned
@ -42,12 +63,12 @@ namespace Loki
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
// (such as unsigned __int64 or unsigned long long int) with the TypeTraits
// class template defined below.
// Invocation: IsCustomSignedInt<T> where T is any type
// Defines 'value', an enum that is 1 iff T is a custom built-in signed
@ -60,7 +81,7 @@ namespace Loki
struct IsCustomSignedInt
{
enum { value = 0 };
};
};
////////////////////////////////////////////////////////////////////////////////
// class template IsCustomFloat
@ -77,7 +98,7 @@ namespace Loki
struct IsCustomFloat
{
enum { value = 0 };
};
};
////////////////////////////////////////////////////////////////////////////////
// Helper types for class template TypeTraits defined below
@ -91,7 +112,7 @@ namespace Loki
typedef TYPELIST_3(bool, char, wchar_t) StdOtherInts;
typedef TYPELIST_3(float, double, long double) StdFloats;
}
////////////////////////////////////////////////////////////////////////////////
// class template TypeTraits
// Figures out various properties of any given type
@ -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)
};
};
struct EnumFalse{ enum {value = 0};};
struct EnumTrue{ enum {value = 1};};
// 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))};
};
};
template<bool IsRef>
struct AdjReference
{
@ -166,25 +268,33 @@ 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(...);
private:
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&.
// This function can only be used if T is not a reference-Type.
@ -194,109 +304,150 @@ namespace Loki
// references.
// 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 T, class U>
static Private::YES is_pointer2member(U T::*);
static Private::NO is_pointer2member(...);
template <class U>
static Private::NO IsReferenceHelper2(U&(*)(Private::Wrap<U>));
static Private::YES IsReferenceHelper2(...);
// 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;
enum { isStdUnsignedInt =
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 =
enum { isStdSignedInt =
TL::IndexOf<Private::StdSignedInts, T>::value >= 0 };
enum { isStdIntegral = isStdUnsignedInt || isStdSignedInt ||
TL::IndexOf<Private::StdOtherInts, T>::value >= 0 };
enum { isStdFloat = TL::IndexOf<Private::StdFloats, T>::value >= 0 };
enum { isStdArith = isStdIntegral || isStdFloat };
enum { isStdFundamental = isStdArith || isStdFloat || isVoid };
enum { isUnsignedInt = isStdUnsignedInt || IsCustomUnsignedInt<T>::value };
enum { isSignedInt = isStdSignedInt || IsCustomSignedInt<T>::value };
enum { isIntegral = isStdIntegral || isUnsignedInt || isSignedInt };
enum { isFloat = isStdFloat || IsCustomFloat<T>::value };
enum { isArith = isIntegral || isFloat };
enum { isFundamental = isStdFundamental || isArith || isFloat };
enum {
isConst =
sizeof(is_const(Wrap<T>())) == sizeof(Private::YES)
enum {
isConst = Private::IsConstImpl
<isReference, isArray>::template In<T>::value
};
enum {
isVolatile =
sizeof(is_volatile(Wrap<T>())) == sizeof(Private::YES)
enum {
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;
template In<T>::Result AdjType;
public:
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:
typedef typename Select
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
// (but works for other incomplete types)
// (the boost one (Paul Mensonides) is better)
//
enum { isClass =
!isScalar &&
!isArray &&
enum { isClass =
!isScalar &&
!isArray &&
!isReference &&
!isVoid
!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
// 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_