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 Loki VC 6.0 Port or how to produce C1001 - Internal Compiler Errors
------------------------------------------------------------------- -------------------------------------------------------------------
Version: 0.3a Version: 0.3b
Introduction/Compatibility: Introduction/Compatibility:
--------------------------- ---------------------------
@ -30,35 +30,44 @@ If you use Singletons with longevity you must add Singleton.cpp to your project/
Fixes: Fixes:
------ ------
Jan 12, 2003: Jan 30, 2003:
------------- -------------
* changed the signature of SmallObject's op new. Now it * In TypeTraits.h: Fixed bugs in TypeTraits' scalar and array detection.
matches the corresponding op delete. 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. Thanks to M.Yamada for the hint and the solution.
Dec 08, 2002: Dec 08, 2002:
------------- -------------
* In HierarchyGenerators.h: Sergey Khachatrian reported a bug * In HierarchyGenerators.h: Sergey Khachatrian reported a bug
in GenScatterHierarchy when used with a typelist containing in GenScatterHierarchy when used with a typelist containing
equal types (e.g. GenScatterHierarchy<TYPELIST_2(int, int), UnitWrapper> equal types (e.g. GenScatterHierarchy<TYPELIST_2(int, int), UnitWrapper>
resp. Tuple<TYPELIST_2(int, int)>) resp. Tuple<TYPELIST_2(int, int)>)
Fixing the bug I found another MSVC6-Problem in the Field-function. Fixing the bug I found another MSVC6-Problem in the Field-function.
The workaround for this problems results in an interface change. 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 Dec 03, 2002
------------- -------------
* In MSVC6Helpers.h: The original version failed to qualify some types from the * In MSVC6Helpers.h: The original version failed to qualify some types from the
Private-Namespace. Private-Namespace.
Thanks to Adi Shavit for pointing that out Thanks to Adi Shavit for pointing that out
* In Threads.h: Changed wrong ctor/dtor names in ObjectLevelLockable. * In Threads.h: Changed wrong ctor/dtor names in ObjectLevelLockable.
Thanks to Adi Shavit for pointing that out Thanks to Adi Shavit for pointing that out
Nov 19, 2002: Nov 19, 2002:
------------- -------------
* In SmartPtr.h: Changed template ctors. See Notes. * In SmartPtr.h: Changed template ctors. See Notes.
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. Unfortunately the MSVC 6.0 supports neither of them.
A. I used various techniques to simulate partial template specialization. In some cases 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 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 possible (or better: i did not find a proper solution). In any case it leads
to increasing code complexity :-) to increasing code complexity :-)
B. One way to simulate template template parameters is to replace the template class with 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 a normal class containing a nested template class. You then move the original functionality
to the nested class. to the nested class.
The problem with this approach is MSVC's 'dependent template typedef bug'. MSVC 6.0 does not The problem with this approach is MSVC's 'dependent template typedef bug'. MSVC 6.0 does not
allow something like this: allow something like this:
[code] [code]
template <class APolicy, class T> template <class APolicy, class T>
struct Foo struct Foo
{ {
// 'error C1001 - Internal Compiler Error' here // 'error C1001 - Internal Compiler Error' here
typedef typename APolicy::template In<T> type; 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 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, simulate template template parameters. This approach works fine with MSVC 6.0. But be warned,
this technique uses not valid C++. this technique uses not valid C++.
Of course, replacing template template parameters always results in some interface changes. 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 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 argument specification. These dummy-Parameters help the compiler in deducing the template
parameters that otherwise need to be explicitly specified. parameters that otherwise need to be explicitly specified.
Example: Example:
[code] [code]
struct Foo struct Foo
{ {
template <class T> template <class T>
T Func(); T Func();
}; };
[/code] [/code]
becomes becomes
[code] [code]
struct Foo struct Foo
{ {
template <class T> template <class T>
T Func(T* pDummy1); T Func(T* pDummy1);
}; };
[/code] [/code]
in this port. in this port.
Update: Update:
------- -------
The MSVC 6.0 sometimes does not overload normal functions depending The MSVC 6.0 sometimes does not overload normal functions depending
on explicit argument specification correctly (see: Microsoft KB Article - 240871) on explicit argument specification correctly (see: Microsoft KB Article - 240871)
The following code demonstrates the problem: The following code demonstrates the problem:
[code] [code]
template <unsigned i, class T> template <unsigned i, class T>
void BugDemonstration(T p) void BugDemonstration(T p)
{ {
printf("BugDemonstration called with i = %d\n", i); printf("BugDemonstration called with i = %d\n", i);
} }
int main() int main()
{ {
GenScatterHierarchy<TYPELIST_3(int, int, int), TestUnitWrapper> Bla; GenScatterHierarchy<TYPELIST_3(int, int, int), TestUnitWrapper> Bla;
// will always print: "BugDemonstration called with i = 2"; // will always print: "BugDemonstration called with i = 2";
BugDemonstration<0>(Bla); BugDemonstration<0>(Bla);
BugDemonstration<1>(Bla); BugDemonstration<1>(Bla);
BugDemonstration<2>(Bla); BugDemonstration<2>(Bla);
} }
[/code] [/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) 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 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). 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 E. All template parameters that have a default type of void in the original lib now
have int as default type. have int as default type.
F. In Functor.h I changed a ResultType of type void to VoidAsType (an udt). This change is transparent F. In Functor.h I changed a ResultType of type void to VoidAsType (an udt). This change is
for the user of Functor. transparent to the user of Functor.
Because I could not think of any general and transparent workaround I followed different 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. 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 In other places (for example: MultiMethod.h) this port simply fails to support void as
return type :-( return type :-(
Some words to template-ctors resp. template assignment operators: Some words to template-ctors resp. template assignment operators:
The MSVC 6.0 introduces an order-dependency for template ctor The MSVC 6.0 introduces an order-dependency for template ctor
@ -168,11 +177,11 @@ So instead of
template <class T> template <class T>
struct Foo struct Foo
{ {
Foo(const Foo&) Foo(const Foo&)
{} {}
template <class U> template <class U>
Foo(const Foo<U>& r) Foo(const Foo<U>& r)
{} {}
}; };
[/code] [/code]
you *need* to write: you *need* to write:
@ -180,12 +189,12 @@ you *need* to write:
template <class T> template <class T>
struct Foo struct Foo
{ {
template <class U> template <class U>
Foo(const Foo<U>& r) Foo(const Foo<U>& r)
{} {}
Foo(const Foo& r) Foo(const Foo& r)
{} {}
}; };
[/code] [/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> template <class T>
struct Foo struct Foo
{ {
template <class Fun> template <class Fun>
Foo(Fun r) Foo(Fun r)
{} {}
Foo(const Foo& r) Foo(const Foo& r)
{} {}
}; };
[/code] [/code]
then the VC will no longer find a copy-ctor. then the VC will no longer find a copy-ctor.
@ -214,111 +223,122 @@ Interface changes:
------------------ ------------------
1. In Threads.h: 1. In Threads.h:
* Thread-Policies changed from class templates to normal classes containing a * Thread-Policies changed from class templates to normal classes containing a
nested class template 'In'. nested class template 'In'.
consequences: consequences:
This change is not very dramatic because it won't break code using this port when 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) switching to the original library (only new Thread-Policies must be changed)
2. In Singleton.h: 2. In Singleton.h:
* The Creation- and Lifetime-Policies are no longer class templates. Instead they all use * The Creation- and Lifetime-Policies are no longer class templates. Instead they all use
Member-Templates. Member-Templates.
consequences: consequences:
Again this change will only break new Policies when switching to the Again this change will only break new Policies when switching to the
original library. original library.
3. In Functor.h: 3. In Functor.h:
* No covariant return types. * No covariant return types.
consequences: consequences:
DoClone always returns a FunctorImplBase<R, ThreadingModel>* where R is the functor's return DoClone always returns a FunctorImplBase<R, ThreadingModel>* where R is the functor's return
type and ThreadingModel its current ThreadingModel. type and ThreadingModel its current ThreadingModel.
4. TypeTraits.h 4. TypeTraits.h
* Because VC 6.0 lacks partial template specialization, the TypeTraits-Class provides not * Because VC 6.0 lacks partial template specialization, the TypeTraits-Class
all the stuff provided by the original library's version. 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 5. HierarchyGenerator.h
* I used Mat Marcus' approach to port GenScatterHierarchy. * I used Mat Marcus' approach to port GenScatterHierarchy.
See http://lists.boost.org/MailArchives/boost/msg20915.php) for the consequences. 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: consequences:
For every concrete unit-template there must be a normal class containing 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 a nested-template class called 'In'. 'In' should only contain a typedef to the
concrete Unit. concrete Unit.
Update: Update:
The port's original version of GenScatterHierarchy does not work when used The port's original version of GenScatterHierarchy does not work when used
with typelists containing equal types. with typelists containing equal types.
The problem is due to a VC bug. The VC fails to compile code similar The problem is due to a VC bug. The VC fails to compile code similar
to this, although it is perfectly legal. to this, although it is perfectly legal.
[code] [code]
template <class T> template <class T>
class Wrapper class Wrapper
{}; {};
template <class T> template <class T>
struct B : public Wrapper<T> struct B : public Wrapper<T>
{}; {};
// ERROR: 'A<T>' : direct base 'Wrapper<T>' is inaccessible; already a base of 'B<T>' // ERROR: 'A<T>' : direct base 'Wrapper<T>' is inaccessible; already a base of 'B<T>'
template <class T> template <class T>
class A : public B<T>, public Wrapper<T> class A : public B<T>, public Wrapper<T>
{}; {};
[/code] [/code]
Unfortunately my workaround has a big drawback. Unfortunately my workaround has a big drawback.
GenScatterHierarchy now has to generate a lot more classes. GenScatterHierarchy now has to generate a lot more classes.
Alexandrescu's original implementation generates 3*n classes (n - number of types in the typelist) 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 old version of my port creates 4 * n + 1
The new version will create 5 * n The new version will create 5 * n
The fix also reveals the "Explicitly Specified Template Functions Not Overloaded Correctly"-Bug 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. (Microsoft KB Article - 240871) in the Field-Function taking a nontype int Parameter.
This leads to an interface change: This leads to an interface change:
Instead of: Field<0>(obj) Instead of: Field<0>(obj)
one now has to write one now has to write
Field(obj, Int2Type<0>()); Field(obj, Int2Type<0>());
I added a macro FIELD. Using this macro one can write I added a macro FIELD. Using this macro one can write
FIELD(obj, 0) FIELD(obj, 0)
6. Factory.h 6. Factory.h
* The Error-Policy for Factory and CloneFactory is no longer a template template parameter. * The Error-Policy for Factory and CloneFactory is no longer a template template parameter.
Use a class with member-templates instead. Use a class with member-templates instead.
consequences: consequences:
This change will only break new Policies when switching to the This change will only break new Policies when switching to the
original library. original library.
7. AbstractFactory.h 7. AbstractFactory.h
* no covariant return types * no covariant return types
* no template template parameters * no template template parameters
For every concrete Factory-Unit there must be a normal class containing 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 a nested-template class called 'In'. 'In' shall contain a typedef to the
concrete Factory-Unit. concrete Factory-Unit.
* Added a dummy-Parameter to AbstractFactory::Create (see C.) * Added a dummy-Parameter to AbstractFactory::Create (see C.)
Calling syntax changed from: Calling syntax changed from:
ConcProduct* p = aFactory.Create<ConcProduct>(); ConcProduct* p = aFactory.Create<ConcProduct>();
to to
ConcProduct* p = aFactory.Create((ConcProduct*)0); ConcProduct* p = aFactory.Create((ConcProduct*)0);
8. SmartPtr.h 8. SmartPtr.h
@ -330,26 +350,27 @@ Interface changes:
9. Visitor.h 9. Visitor.h
* no template template parameters * no template template parameters
(see 7.for a description of the consequences) (see 7.for a description of the consequences)
* This port fails to correctly support void return types. As a workaround it provides * 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 a set of complete new classes (and macros) for void. Default arguments of type void
were replaced by arguments of type int. were replaced by arguments of type int.
10. MultiMethods.h 10. MultiMethods.h
* replaced all template template parameters with 'normal' parameters (see 7. * replaced all template template parameters with 'normal' parameters (see 7.
for a description of the consequences) 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 * dummy parameters were added to functions that otherwise would depend on
explicit template argument specification (14.8.1). explicit template argument specification (14.8.1).
More info: More info:
---------- ----------
The original Loki library can be found here: http://moderncppdesign.com 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 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 // The Loki Library
// Copyright (c) 2001 by Andrei Alexandrescu // Copyright (c) 2001 by Andrei Alexandrescu
// This code accompanies the book: // 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. // Patterns Applied". Copyright (c) 2001. Addison-Wesley.
// Permission to use, copy, modify, distribute and sell this software for any // Permission to use, copy, modify, distribute and sell this software for any
// purpose is hereby granted without fee, provided that the above copyright // purpose is hereby granted without fee, provided that the above copyright
// notice appear in all copies and that both that copyright notice and this // notice appear in all copies and that both that copyright notice and this
// permission notice appear in supporting documentation. // permission notice appear in supporting documentation.
// The author or Addison-Welsey Longman make no representations about the // The author or Addison-Welsey Longman make no representations about the
// suitability of this software for any purpose. It is provided "as is" // suitability of this software for any purpose. It is provided "as is"
// without express or implied warranty. // without express or implied warranty.
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Last update: Oct 05, 2002 // Last update: Jan 31, 2003
// Most of the code is taken from Rani Sharoni's Loki VC 7 port // This VC 6 port of TypeTraits is based on Rani Sharoni's Loki VC 7 port.
// Reference, pointer and array detection is based on boost's type traits // 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 // AdjReference has moved to namespace-scope. Explicit specialization is
// only allowed there. // 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_ #ifndef TYPETRAITS_INC_
#define 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" #include "Typelist.h"
namespace Loki namespace Loki
@ -29,7 +50,7 @@ namespace Loki
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// class template IsCustomUnsignedInt // class template IsCustomUnsignedInt
// Offers a means to integrate nonstandard built-in unsigned integral types // 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. // class template defined below.
// Invocation: IsCustomUnsignedInt<T> where T is any type // Invocation: IsCustomUnsignedInt<T> where T is any type
// Defines 'value', an enum that is 1 iff T is a custom built-in unsigned // Defines 'value', an enum that is 1 iff T is a custom built-in unsigned
@ -42,12 +63,12 @@ namespace Loki
struct IsCustomUnsignedInt struct IsCustomUnsignedInt
{ {
enum { value = 0 }; enum { value = 0 };
}; };
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// class template IsCustomSignedInt // class template IsCustomSignedInt
// Offers a means to integrate nonstandard built-in unsigned integral types // 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. // class template defined below.
// Invocation: IsCustomSignedInt<T> where T is any type // Invocation: IsCustomSignedInt<T> where T is any type
// Defines 'value', an enum that is 1 iff T is a custom built-in signed // Defines 'value', an enum that is 1 iff T is a custom built-in signed
@ -60,7 +81,7 @@ namespace Loki
struct IsCustomSignedInt struct IsCustomSignedInt
{ {
enum { value = 0 }; enum { value = 0 };
}; };
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// class template IsCustomFloat // class template IsCustomFloat
@ -77,7 +98,7 @@ namespace Loki
struct IsCustomFloat struct IsCustomFloat
{ {
enum { value = 0 }; enum { value = 0 };
}; };
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Helper types for class template TypeTraits defined below // 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(bool, char, wchar_t) StdOtherInts;
typedef TYPELIST_3(float, double, long double) StdFloats; typedef TYPELIST_3(float, double, long double) StdFloats;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// class template TypeTraits // class template TypeTraits
// Figures out various properties of any given type // Figures out various properties of any given type
@ -146,13 +167,94 @@ namespace Loki
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
namespace Private 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};}; // const-detection based on boost's
struct EnumTrue{ enum {value = 1};}; // 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> template<bool IsRef>
struct AdjReference struct AdjReference
{ {
@ -166,25 +268,33 @@ namespace Loki
template<typename U> template<typename U>
struct In { typedef U Result; }; 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> template <typename T>
class TypeTraits class TypeTraits
{ {
private:
static T MakeT(...); private:
template <class U> struct Wrap{}; static Private::YES IsPointer(Private::PointerHelper);
struct pointer_helper static Private::NO IsPointer(...);
{
pointer_helper(const volatile void*);
};
static Private::YES is_pointer(pointer_helper);
static Private::NO is_pointer(...);
// With the VC 6. Rani Sharoni's approach to detect references unfortunately // 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 // is_reference_helper1 is a function taking a Wrap<T> returning
// a pointer to a function taking a Wrap<T> returning a T&. // 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. // This function can only be used if T is not a reference-Type.
@ -194,109 +304,150 @@ namespace Loki
// references. // references.
// In order to detect a reference, use the return-type of is_reference_helper1 // In order to detect a reference, use the return-type of is_reference_helper1
// with is_reference_helper2. // with is_reference_helper2.
// //
// this reference-detection approach is based on boost's template <class U>
// Type-Traits. See: boost::composite_traits.h static U&(* IsReferenceHelper1(Private::Wrap<U>) )(Private::Wrap<U>);
template <class T> static Private::NO IsReferenceHelper1(...);
static T&(* is_reference_helper1(Wrap<T>) )(Wrap<T>);
static Private::NO is_reference_helper1(...);
template <class T> template <class U>
static Private::NO is_reference_helper2(T&(*)(Wrap<T>)); static Private::NO IsReferenceHelper2(U&(*)(Private::Wrap<U>));
static Private::YES is_reference_helper2(...); 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 template <class U, class Z>
// functions can't return arrays. static Private::YES IsPointer2Member(Z U::*);
// this array-detection approach is based on boost's static Private::NO IsPointer2Member(...);
// Type-Traits. See: boost::array_traits.h struct DummyType{};
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(...);
public: public:
enum {isArray = Private::ArrayTester<T>::value};
enum {isReference = sizeof( enum {isReference = sizeof(
is_reference_helper2( IsReferenceHelper2(
is_reference_helper1(Wrap<T>()))) == sizeof(Private::YES)}; IsReferenceHelper1(Private::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)};
enum {isVoid = Private::IsVoid<T>::value}; 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 }; TL::IndexOf<Private::StdUnsignedInts, T>::value >= 0 };
enum { isStdSignedInt = enum { isStdSignedInt =
TL::IndexOf<Private::StdSignedInts, T>::value >= 0 }; TL::IndexOf<Private::StdSignedInts, T>::value >= 0 };
enum { isStdIntegral = isStdUnsignedInt || isStdSignedInt || enum { isStdIntegral = isStdUnsignedInt || isStdSignedInt ||
TL::IndexOf<Private::StdOtherInts, T>::value >= 0 }; TL::IndexOf<Private::StdOtherInts, T>::value >= 0 };
enum { isStdFloat = TL::IndexOf<Private::StdFloats, T>::value >= 0 }; enum { isStdFloat = TL::IndexOf<Private::StdFloats, T>::value >= 0 };
enum { isStdArith = isStdIntegral || isStdFloat }; enum { isStdArith = isStdIntegral || isStdFloat };
enum { isStdFundamental = isStdArith || isStdFloat || isVoid }; enum { isStdFundamental = isStdArith || isStdFloat || isVoid };
enum { isUnsignedInt = isStdUnsignedInt || IsCustomUnsignedInt<T>::value }; enum { isUnsignedInt = isStdUnsignedInt || IsCustomUnsignedInt<T>::value };
enum { isSignedInt = isStdSignedInt || IsCustomSignedInt<T>::value }; enum { isSignedInt = isStdSignedInt || IsCustomSignedInt<T>::value };
enum { isIntegral = isStdIntegral || isUnsignedInt || isSignedInt }; enum { isIntegral = isStdIntegral || isUnsignedInt || isSignedInt };
enum { isFloat = isStdFloat || IsCustomFloat<T>::value }; enum { isFloat = isStdFloat || IsCustomFloat<T>::value };
enum { isArith = isIntegral || isFloat }; enum { isArith = isIntegral || isFloat };
enum { isFundamental = isStdFundamental || isArith || isFloat }; enum { isFundamental = isStdFundamental || isArith || isFloat };
enum { enum {
isConst = isConst = Private::IsConstImpl
sizeof(is_const(Wrap<T>())) == sizeof(Private::YES) <isReference, isArray>::template In<T>::value
}; };
enum { enum {
isVolatile = isVolatile = Private::IsVolatileImpl
sizeof(is_volatile(Wrap<T>())) == sizeof(Private::YES) <isReference, isArray>::template In<T>::value
}; };
enum { isScalar = isStdArith || isPointer || isMemberPointer};
private: private:
typedef typename Private::AdjReference<isReference || isVoid>:: 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 isScalar || isArray, T, AdjType
> >
::Result ParameterType; ::Result ParameterType;
//
//
// We get is_class for free // We get is_class for free
// BUG - fails with functions types (ICE) and unknown size array // BUG - fails with functions types (ICE) and unknown size array
// (but works for other incomplete types) // (but works for other incomplete types)
// (the boost one (Paul Mensonides) is better) // (the boost one (Paul Mensonides) is better)
// //
enum { isClass = enum { isClass =
!isScalar && !isScalar &&
!isArray && !isArray &&
!isReference && !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: // Change log:
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!! // 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) // 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_ #endif // TYPETRAITS_INC_