//////////////////////////////////////////////////////////////////////////////// // 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: Dec 08, 2002 #ifndef HIERARCHYGENERATORS_INC_ #define HIERARCHYGENERATORS_INC_ #define IS_TYPELIST(TList) TL::Private::IsTypelist #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 // 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 struct TestUnit {}; // void Func(TestUnit); // int main() // { // GenScatterHierarchy, TestUnit> obj; // Func(obj); // calls Func(TestUnit) // } // // Using this port the code would become: // class Foo {}; // template struct TestUnit {}; // struct TestUnitWrapper // { // template struct In {typedef TestUnit type}; // }; // void Func(TestUnit); // int main() // { // GenScatterHierarchy, TestUnitWrapper> obj; // Func(obj); // calls Func(TestUnit) // } // // Not very nice, i know :-( // // See "Metaprogramming VC++ - more of Loki ported" from Mat Marcus // (http://lists.boost.org/MailArchives/boost/msg20915.php) // // Update: // ------- // The first version of GenScatterHierarchy did not work with typelists // containing equal types. The MSVC 6.0 erroneously complains about // inaccessible base-classes (error C2584). // This new version adds Dummy-classes to the left branch of the generated // hierarchy to workaround this VC-Bug. // It creates hierarchies like this: // // Holder NullType // \ / //Holder GenScatter GenScatter // \ \ / //VC_InaccessibleBase InheritFromTo // \ | //GenScatter GenScatter // \ / // InheritFromTo // | // | //GenScatter // // Of course this version of GenScatterHierarchy generates a lot more // classes (5*n) than Alexandrescu's original implementation (3*n) // template class GenScatterHierarchy; namespace Private { template struct InheritFromTwo : public T, public U { }; template struct GenScatterImpl; // Specialization for a general typelist template <> struct GenScatterImpl { template struct In : public GenScatterHierarchy { typedef InheritFromTwo < VC_InaccessibleBase, typename T::Tail>, GenScatterHierarchy > type; typedef VC_InaccessibleBase,typename T::Tail> LeftBase; typedef GenScatterHierarchy RightBase; }; }; // Specialization for a typelist with only one element template <> struct GenScatterImpl { template struct In : public GenScatterHierarchy { // for the last Holder-class no dummy class is needed. typedef InheritFromTwo < GenScatterHierarchy, GenScatterHierarchy > type; typedef GenScatterHierarchy LeftBase; typedef GenScatterHierarchy RightBase; }; }; // Specialization for a single type template <> struct GenScatterImpl { template struct In { typedef typename ApplyInnerType::type type; typedef type LeftBase; typedef EmptyType RightBase; //typedef AtomicType::THIS_SELECTED bla; }; }; // Specialization for NullType template <> struct GenScatterImpl { template struct In { typedef EmptyType type; typedef type LeftBase; typedef type RightBase; }; }; } // end namespace Private template class GenScatterHierarchy : public Private::GenScatterImpl < IS_TYPELIST(T)::type_id >::template In::type { public: typedef typename Select < TL::Private::IsTypelist::value, T, void >::Result TList; typedef typename Private::GenScatterImpl < IS_TYPELIST(T)::type_id >::template In::LeftBase LeftBase; typedef typename Private::GenScatterImpl < IS_TYPELIST(T)::type_id >::template In::RightBase RightBase; template struct Rebind { typedef ApplyInnerType::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(obj) // returns a reference to Unit, where Unit is the template used to generate H //////////////////////////////////////////////////////////////////////////////// template typename ApplyInnerType::type& Field(GenScatterHierarchy& obj) { return obj; } template const typename ApplyInnerType::type& Field(const GenScatterHierarchy& obj) { return obj; } //////////////////////////////////////////////////////////////////////////////// // function template TupleUnit // The building block of tuples //////////////////////////////////////////////////////////////////////////////// template 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 struct In { typedef TupleUnit type; }; }; } template struct Tuple : public GenScatterHierarchy { }; //////////////////////////////////////////////////////////////////////////////// // helper class template FieldHelper // See Field below //////////////////////////////////////////////////////////////////////////////// template struct FieldHelper { template struct In { private: typedef typename TL::TypeAt::Result ElementType; typedef typename ApplyInnerType::type UnitType; enum { isConst = TypeTraits::isConst }; typedef typename Select < isConst, const typename H::RightBase, typename H::RightBase > ::Result RightBase; typedef typename Select < IsEqualType >::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 static ResultType& Do(H& obj, T*) { //typedef typename T::RightBase RightBase; //RightBase& rightBase = obj; RightBase& rightBase = obj; return FieldHelper::template In::Do(rightBase, (int*)0); } }; }; template <> struct FieldHelper<0> { template struct In { private: typedef typename H::TList::Head ElementType; typedef typename ApplyInnerType::type UnitType; enum { isConst = TypeTraits::isConst }; typedef typename Select < isConst, const typename H::LeftBase, typename H::LeftBase > ::Result LeftBase; typedef typename Select < IsEqualType >::value, ElementType, UnitType > ::Result UnqualifiedResultType; public: typedef typename Select < isConst, const UnqualifiedResultType, UnqualifiedResultType > ::Result ResultType; public: template static ResultType& Do(H& obj, T*) { 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(obj) // returns a reference to Unit, where Unit is the template used to generate H // and T is the i-th type in the typelist //////////////////////////////////////////////////////////////////////////////// template typename FieldHelper::template In,UnitWrapper>::ResultType& Field(GenScatterHierarchy& obj, Int2Type) { typedef typename GenScatterHierarchy H; return FieldHelper::template In::Do(obj, (int*)0); } //////////////////////////////////////////////////////////////////////////////// // 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 //////////////////////////////////////////////////////////////////////////////// // VC 6.0 changes: // see GenScatterHierarchy template < class TList, class Unit, class Root = EmptyType > class GenLinearHierarchy; namespace Private { template struct GenLinearHierarchyHelper { template struct In { typedef typename TList::ERROR_THIS_INSTANCE_SELECTED Result; }; }; template <> struct GenLinearHierarchyHelper { template struct In { private: typedef typename TList::Head Head; typedef typename TList::Tail Tail; public: typedef typename ApplyInnerType2 >::type Result; }; }; template <> struct GenLinearHierarchyHelper { template struct In { private: typedef typename TList::Head Head; public: typedef typename ApplyInnerType2::type Result; }; }; template struct Wrap { struct Dummy {}; typedef typename T::Tail Tail; // create the hierarchy typedef typename Private::GenLinearHierarchyHelper < typename TL::Private::IsTypelist::type_tag > ::template In::Result TempType; typedef Private::VC_Base_Workaround 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 typename 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::Base { ASSERT_TYPELIST(TList); // TList must not be NullType public: typedef typename Private::GenLinearHierarchyHelper < typename TL::Private::IsTypelist::type_tag > ::template In::Result LinBase; }; } // namespace Loki #if defined (_MSC_VER) && _MSC_VER <= 1300 #define FIELD(Obj, Nr) \ Field(Obj, Int2Type()) #else #define FIELD(Obj, Nr) \ Field(Obj) #endif //////////////////////////////////////////////////////////////////////////////// // 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 // Dec 08, 2002: Fixed problems with MSVC6-Version of GenScatterHierarchy when // used with typelists containing equal types. B.K. // New Version is ugly :-( // Dec 08, 2002: Interface changed for Field-Function. The old version does not // work correctly due to the "Explicitly Specified Template // Functions Not Overloaded Correctly"-Bug // (Microsoft KB Article - 240871). B.K. //////////////////////////////////////////////////////////////////////////////// #undef IS_TYPELIST #endif // HIERARCHYGENERATORS_INC_