461 lines
14 KiB
C
461 lines
14 KiB
C
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
// The Loki Library
|
||
|
// Copyright (c) 2001 by Andrei Alexandrescu
|
||
|
// This code accompanies the book:
|
||
|
// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design
|
||
|
// Patterns Applied". Copyright (c) 2001. Addison-Wesley.
|
||
|
// 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-Wesley 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 24, 2002
|
||
|
|
||
|
#ifndef HIERARCHYGENERATORS_INC_
|
||
|
#define HIERARCHYGENERATORS_INC_
|
||
|
|
||
|
#define IS_TYPELIST(TList) TL::Private::IsTypelist<TList>
|
||
|
|
||
|
#include "Typelist.h"
|
||
|
#include "TypeTraits.h"
|
||
|
#include "EmptyType.h"
|
||
|
#include "MSVC6Helpers.h"
|
||
|
namespace Loki
|
||
|
{
|
||
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
// class template GenScatterHierarchy
|
||
|
// Generates a scattered hierarchy starting from a typelist and a template
|
||
|
// Invocation (TList is a typelist, Model is a template of one arg):
|
||
|
// GenScatterHierarchy<TList, Model>
|
||
|
// The generated class inherits all classes generated by instantiating the
|
||
|
// template 'Model' with the types contained in TList
|
||
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
// VC 6.0 changes:
|
||
|
// * Unit is no longer a template template parameter.
|
||
|
// * 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.
|
||
|
//
|
||
|
// Using the originial library one would write something like this:
|
||
|
// class Foo {};
|
||
|
// template <class T> struct TestUnit {};
|
||
|
// void Func(TestUnit<Foo>);
|
||
|
// int main()
|
||
|
// {
|
||
|
// GenScatterHierarchy<Typelist<Foo, NullType>, TestUnit> obj;
|
||
|
// Func(obj); // calls Func(TestUnit<Foo>)
|
||
|
// }
|
||
|
//
|
||
|
// Using this port the code would become:
|
||
|
// class Foo {};
|
||
|
// template <class T> struct TestUnit {};
|
||
|
// struct TestUnitWrapper
|
||
|
// {
|
||
|
// template <class T> struct In {typedef TestUnit<T> type};
|
||
|
// };
|
||
|
// void Func(TestUnit<Foo>);
|
||
|
// int main()
|
||
|
// {
|
||
|
// GenScatterHierarchy<Typelist<Foo, NullType>, TestUnitWrapper> obj;
|
||
|
// Func(obj); // calls Func(TestUnit<Foo>)
|
||
|
// }
|
||
|
//
|
||
|
// Not very nice, i know :-(
|
||
|
//
|
||
|
// See "Metaprogramming VC++ - more of Loki ported" from Mat Marcus
|
||
|
// (http://lists.boost.org/MailArchives/boost/msg20915.php)
|
||
|
|
||
|
template <class TList, class Unit> class GenScatterHierarchy;
|
||
|
|
||
|
namespace Private
|
||
|
{
|
||
|
template <class T, class U>
|
||
|
class InheritFromTwo : public T, public U
|
||
|
{
|
||
|
public:
|
||
|
};
|
||
|
|
||
|
template <int tag>
|
||
|
struct GenScatterImpl;
|
||
|
|
||
|
// Specialization for a general typelist
|
||
|
template <>
|
||
|
struct GenScatterImpl<TL::Private::Typelist_ID>
|
||
|
{
|
||
|
template <class T, class MetaFunctionWrapper>
|
||
|
struct In : public GenScatterHierarchy<typename T::Head,MetaFunctionWrapper>
|
||
|
{
|
||
|
typedef
|
||
|
InheritFromTwo < GenScatterHierarchy<typename T::Head,
|
||
|
MetaFunctionWrapper>,
|
||
|
GenScatterHierarchy<typename T::Tail,
|
||
|
MetaFunctionWrapper>
|
||
|
> type;
|
||
|
typedef GenScatterHierarchy<typename T::Head, MetaFunctionWrapper> LeftBase;
|
||
|
typedef GenScatterHierarchy<typename T::Tail, MetaFunctionWrapper> RightBase;
|
||
|
};
|
||
|
};
|
||
|
|
||
|
// Specialization for a single type
|
||
|
template <>
|
||
|
struct GenScatterImpl<TL::Private::NoneList_ID>
|
||
|
{
|
||
|
template <class AtomicType, class MetaFunctionWrapper>
|
||
|
struct In
|
||
|
{
|
||
|
typedef typename
|
||
|
ApplyInnerType<MetaFunctionWrapper, AtomicType>::type type;
|
||
|
typedef type LeftBase;
|
||
|
typedef EmptyType RightBase;
|
||
|
};
|
||
|
};
|
||
|
|
||
|
// Specialization for NullType
|
||
|
template <>
|
||
|
struct GenScatterImpl<TL::Private::NullType_ID>
|
||
|
{
|
||
|
template <class NullTypeList, class MetaFunctionWrapper>
|
||
|
struct In
|
||
|
{
|
||
|
typedef EmptyType type;
|
||
|
typedef type LeftBase;
|
||
|
typedef type RightBase;
|
||
|
};
|
||
|
};
|
||
|
} // end namespace Private
|
||
|
|
||
|
template <class T, class Unit>
|
||
|
class GenScatterHierarchy : public Private::GenScatterImpl
|
||
|
<
|
||
|
IS_TYPELIST(T)::type_id == TL::Private::Typelist_ID ? TL::Private::Typelist_ID :
|
||
|
IS_TYPELIST(T)::type_id == TL::Private::AtomList_ID ? TL::Private::Typelist_ID :
|
||
|
IS_TYPELIST(T)::type_id == TL::Private::NullType_ID ? TL::Private::NullType_ID :
|
||
|
TL::Private::NoneList_ID
|
||
|
>::template In<T, Unit>::type
|
||
|
{
|
||
|
public:
|
||
|
typedef typename Select
|
||
|
<
|
||
|
TL::Private::IsTypelist<T>::value, T, void
|
||
|
>::Result TList;
|
||
|
typedef typename Private::GenScatterImpl
|
||
|
<
|
||
|
IS_TYPELIST(T)::type_id == TL::Private::Typelist_ID ? TL::Private::Typelist_ID :
|
||
|
IS_TYPELIST(T)::type_id == TL::Private::AtomList_ID ? TL::Private::Typelist_ID :
|
||
|
IS_TYPELIST(T)::type_id == TL::Private::NullType_ID ? TL::Private::NullType_ID :
|
||
|
TL::Private::NoneList_ID
|
||
|
>::template In<T, Unit>::LeftBase LeftBase;
|
||
|
|
||
|
typedef typename Private::GenScatterImpl
|
||
|
<
|
||
|
IS_TYPELIST(T)::type_id == TL::Private::Typelist_ID ? TL::Private::Typelist_ID :
|
||
|
IS_TYPELIST(T)::type_id == TL::Private::AtomList_ID ? TL::Private::Typelist_ID :
|
||
|
IS_TYPELIST(T)::type_id == TL::Private::NullType_ID ? TL::Private::NullType_ID :
|
||
|
TL::Private::NoneList_ID
|
||
|
>::template In<T, Unit>::RightBase RightBase;
|
||
|
|
||
|
template <typename U> struct Rebind
|
||
|
{
|
||
|
typedef ApplyInnerType<Unit, U>::type Result;
|
||
|
};
|
||
|
};
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
// function template Field
|
||
|
// Accesses a field in an object of a type generated with GenScatterHierarchy
|
||
|
// Invocation (obj is an object of a type H generated with GenScatterHierarchy,
|
||
|
// T is a type in the typelist used to generate H):
|
||
|
// Field<T>(obj)
|
||
|
// returns a reference to Unit<T>, where Unit is the template used to generate H
|
||
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
template <class T, class TList, class UnitWrapper>
|
||
|
typename ApplyInnerType<UnitWrapper, T>::type&
|
||
|
Field(GenScatterHierarchy<TList, UnitWrapper>& obj)
|
||
|
{
|
||
|
return obj;
|
||
|
}
|
||
|
|
||
|
template <class T, class TList, class UnitWrapper>
|
||
|
const typename ApplyInnerType<UnitWrapper, T>::type&
|
||
|
Field(const GenScatterHierarchy<TList, UnitWrapper>& obj)
|
||
|
{
|
||
|
return obj;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
// function template TupleUnit
|
||
|
// The building block of tuples
|
||
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
template <class T>
|
||
|
struct TupleUnit
|
||
|
{
|
||
|
T value_;
|
||
|
operator T&() { return value_; }
|
||
|
operator const T&() const { return value_; }
|
||
|
};
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
// class template Tuple
|
||
|
// Implements a tuple class that holds a number of values and provides field
|
||
|
// access to them via the Field function (below)
|
||
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
namespace Private
|
||
|
{
|
||
|
struct TupleUnitWrapper
|
||
|
{
|
||
|
template <class T>
|
||
|
struct In
|
||
|
{
|
||
|
typedef TupleUnit<T> type;
|
||
|
};
|
||
|
};
|
||
|
}
|
||
|
template <class TList>
|
||
|
struct Tuple : public GenScatterHierarchy<TList, Private::TupleUnitWrapper>
|
||
|
{
|
||
|
};
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
// helper class template FieldHelper
|
||
|
// See Field below
|
||
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
template <unsigned int i>
|
||
|
struct FieldHelper
|
||
|
{
|
||
|
template<class H, class Unit>
|
||
|
struct In
|
||
|
{
|
||
|
private:
|
||
|
typedef typename TL::TypeAt<typename H::TList, i>::Result ElementType;
|
||
|
typedef typename ApplyInnerType<Unit, ElementType>::type UnitType;
|
||
|
|
||
|
enum { isConst = TypeTraits<H>::isConst };
|
||
|
|
||
|
typedef typename Select
|
||
|
<
|
||
|
isConst,
|
||
|
const typename H::RightBase,
|
||
|
typename H::RightBase
|
||
|
>
|
||
|
::Result RightBase;
|
||
|
|
||
|
|
||
|
typedef typename Select
|
||
|
<
|
||
|
IsEqualType<UnitType, TupleUnit<ElementType> >::value,
|
||
|
ElementType,
|
||
|
UnitType
|
||
|
>
|
||
|
::Result UnqualifiedResultType;
|
||
|
|
||
|
public:
|
||
|
typedef typename Select
|
||
|
<
|
||
|
isConst,
|
||
|
const UnqualifiedResultType,
|
||
|
UnqualifiedResultType
|
||
|
>
|
||
|
::Result ResultType;
|
||
|
|
||
|
// Must be a template, don't know why.
|
||
|
// If Do is not a template and H& is used as parameter
|
||
|
// MSVC will give a linker error.
|
||
|
template <class T>
|
||
|
static ResultType& Do(T& obj)
|
||
|
{
|
||
|
typedef typename T::RightBase RightBase;
|
||
|
RightBase& rightBase = obj;
|
||
|
return FieldHelper<i - 1>::template In<RightBase, Unit>::Do(rightBase);
|
||
|
}
|
||
|
};
|
||
|
};
|
||
|
|
||
|
template <>
|
||
|
struct FieldHelper<0>
|
||
|
{
|
||
|
template<class H, class Unit>
|
||
|
struct In
|
||
|
{
|
||
|
private:
|
||
|
typedef typename H::TList::Head ElementType;
|
||
|
typedef typename ApplyInnerType<Unit, ElementType>::type UnitType;
|
||
|
|
||
|
enum { isConst = TypeTraits<H>::isConst };
|
||
|
|
||
|
typedef typename Select
|
||
|
<
|
||
|
isConst,
|
||
|
const typename H::LeftBase,
|
||
|
typename H::LeftBase
|
||
|
>
|
||
|
::Result LeftBase;
|
||
|
|
||
|
typedef typename Select
|
||
|
<
|
||
|
IsEqualType<UnitType, TupleUnit<ElementType> >::value,
|
||
|
ElementType,
|
||
|
UnitType
|
||
|
>
|
||
|
::Result UnqualifiedResultType;
|
||
|
|
||
|
public:
|
||
|
typedef typename Select
|
||
|
<
|
||
|
isConst,
|
||
|
const UnqualifiedResultType,
|
||
|
UnqualifiedResultType
|
||
|
>
|
||
|
::Result ResultType;
|
||
|
|
||
|
public:
|
||
|
template <class T>
|
||
|
static ResultType& Do(T& obj)
|
||
|
{
|
||
|
LeftBase& leftBase = obj;
|
||
|
return leftBase;
|
||
|
}
|
||
|
};
|
||
|
};
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
// function template Field
|
||
|
// Accesses a field in an object of a type generated with GenScatterHierarchy
|
||
|
// Invocation (obj is an object of a type H generated with GenScatterHierarchy,
|
||
|
// i is the index of a type in the typelist used to generate H):
|
||
|
// Field<i>(obj)
|
||
|
// returns a reference to Unit<T>, where Unit is the template used to generate H
|
||
|
// and T is the i-th type in the typelist
|
||
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
template <unsigned int i, class TList, class UnitWrapper>
|
||
|
typename FieldHelper<i>::template In<GenScatterHierarchy<TList, UnitWrapper>,UnitWrapper>::ResultType&
|
||
|
Field(GenScatterHierarchy<TList, UnitWrapper>& obj)
|
||
|
{
|
||
|
typedef typename GenScatterHierarchy<TList, UnitWrapper> H;
|
||
|
|
||
|
return FieldHelper<i>::template In<H, UnitWrapper>::Do(obj);
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
// class template GenLinearHierarchy
|
||
|
// Generates a linear hierarchy starting from a typelist and a template
|
||
|
// Invocation (TList is a typelist, Model is a template of two args):
|
||
|
// GenScatterHierarchy<TList, Model>
|
||
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
// VC 6.0 changes:
|
||
|
// see GenScatterHierarchy
|
||
|
|
||
|
template
|
||
|
<
|
||
|
class TList,
|
||
|
class Unit,
|
||
|
class Root = EmptyType
|
||
|
>
|
||
|
class GenLinearHierarchy;
|
||
|
|
||
|
namespace Private
|
||
|
{
|
||
|
|
||
|
template <typename TListTag>
|
||
|
struct GenLinearHierarchyHelper
|
||
|
{
|
||
|
template<class TList, class Unit, class Root>
|
||
|
struct In
|
||
|
{
|
||
|
typedef typename TList::ERROR_THIS_INSTANCE_SELECTED Result;
|
||
|
};
|
||
|
};
|
||
|
|
||
|
template <>
|
||
|
struct GenLinearHierarchyHelper<TL::Private::Typelist_tag>
|
||
|
{
|
||
|
template<class TList, class Unit, class Root>
|
||
|
struct In
|
||
|
{
|
||
|
private:
|
||
|
typedef typename TList::Head Head;
|
||
|
typedef typename TList::Tail Tail;
|
||
|
|
||
|
public:
|
||
|
typedef ApplyInnerType2<Unit, Head, GenLinearHierarchy<Tail, Unit, Root> >::type Result;
|
||
|
};
|
||
|
};
|
||
|
|
||
|
template <>
|
||
|
struct GenLinearHierarchyHelper<TL::Private::NullType_tag>
|
||
|
{
|
||
|
template<class TList, class Unit, class Root>
|
||
|
struct In
|
||
|
{
|
||
|
private:
|
||
|
typedef typename TList::Head Head;
|
||
|
|
||
|
public:
|
||
|
typedef ApplyInnerType2<Unit,Head, Root>::type Result;
|
||
|
};
|
||
|
};
|
||
|
|
||
|
template <class T, class U, class Root>
|
||
|
struct Wrap
|
||
|
{
|
||
|
struct Dummy {};
|
||
|
typedef typename T::Tail Tail;
|
||
|
|
||
|
// create the hierarchy
|
||
|
typedef typename Private::GenLinearHierarchyHelper
|
||
|
<
|
||
|
typename TL::Private::IsTypelist<Tail>::type_tag
|
||
|
>
|
||
|
::template In<T, U, Root>::Result TempType;
|
||
|
|
||
|
typedef typename
|
||
|
Private::VC_Base_Workaround<TempType, Dummy> type;
|
||
|
|
||
|
// this is nothing more than a typedef to the created hierarchy (TempType).
|
||
|
// But if we try to inherit directly from TempType VC 6.0
|
||
|
// will produce a "Error C2516. : is not a legal base class."
|
||
|
typedef type::LeftBase Base;
|
||
|
};
|
||
|
} // namespace Private
|
||
|
|
||
|
// Trying to inherit from LinBase will result in "Error C2516. : is not a legal base class."
|
||
|
// Private::Wrap introduces some levels of indirections which will
|
||
|
// make the vc happy.
|
||
|
template
|
||
|
<
|
||
|
class TList,
|
||
|
class Unit,
|
||
|
class Root
|
||
|
>
|
||
|
class GenLinearHierarchy : public Private::Wrap<TList, Unit, Root>::Base
|
||
|
{
|
||
|
ASSERT_TYPELIST(TList); // TList must not be NullType
|
||
|
|
||
|
public:
|
||
|
typedef typename Private::GenLinearHierarchyHelper
|
||
|
<
|
||
|
typename TL::Private::IsTypelist<typename TList::Tail>::type_tag
|
||
|
>
|
||
|
::template In<TList, Unit, Root>::Result LinBase;
|
||
|
};
|
||
|
|
||
|
} // namespace Loki
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
// Change log:
|
||
|
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
|
||
|
// September 16, 2002: Fixed dependent template, using "::template" syntax. T.S.
|
||
|
// Oct 24, 2002: ported by Benjamin Kaufmann to MSVC 6
|
||
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
#undef IS_TYPELIST
|
||
|
#endif // HIERARCHYGENERATORS_INC_
|