|
Программирование >> Многопоточная библиотека с принципом минимализма
template <class TList, template <class> class unit> class GenScatterHierarchy; Специализация класса GenScatterHierarchy: преобразование класа Typelist в класс Unit template <class Tl, class т2, template <class> class unit> class GenScatterHierarchy<TypeList<Tl, т2>, unit> : public GenScatterHierarchy<Tl, unit>, public GenScatterHierarchy<Tl, unit> public: typedef Typelist<Tl, т2> TList; typedef GenScatterHierarchy<Tl, Unit> LeftBase; typedef GenScatterHierarchy<T2, Unit> RightBase; передача атомарного типа (не списка типов) классу unit template <class AtomicType, template <class> class unit> class GenScatterHierarchy : public Unit<AtopmicType> { typedef unit<AtomicType> LeftBase; С классом NullType не делаем ничего template <template <class> class unit> class GenScatterHierarchy<NullType, unit> { Шаблонный шаблонный параметр работает так, как и ожидалось (глава 1). Шаблонный класс unit передается классу GenScatterHierarchy в качестве второго аргумента. Класс GenScatterHierarchy использует свой шаблонный шаблонный параметр unit как обычный шаблонный класс с одним шаблонным параметром. Новые возможности появляются благодаря тому, что пользователь класса GenScatterHierarchy может передавать ему свой собственный шаблон. Что делает класс GenScatterHierarchy? Если его первый аргумент является атомарным типом (в противоположность списку типов), класс GenScatterHierarchy передает его классу Unit и наследует свойства результируюшего класса unit<T>. Если первый аргумент является списком типов TList, класс GenScatterHierarchy сводится (recurses) к классам GenScatterHierarchy<TList: :Head, unit> и GenScatterHi-erarchy<TList: :Tail, Unit> и наследует их свойства. Класс GenScatterHierar-chy<NullType, unit> является пустым. В итоге процесс конкретизации класса GenScatterHierarchy завершается наследованием класса Unit, конкретизированного каждым типом из списка типов. В качестве примера рассмотрим следующий код. template <class т> struct Holder { т value ; typedef GetScatterHierarchy< TYPELlST 3Cint, string, widget), Holder> widgetinfo; HoldeKWidget> Holder<int> GenScatterHierarchy <Widget,Holder> GenScatterHierarchy <NullType,Holder> Holder<string> GenScatterHierarchy <string,Holder> GenScatterHierarchy <TYPELIST 1 (Wldget),Holder> GenScatterHierarchy <int,Holder> GenScatterHierarchy <TYPELIST 2(string,Widget),Holder> Widgetlnfo Рис. 3.2. Структура наследования класса Widgetlnfo Иерархия наследования, порожденная классом widgetlnfo, показана на рис. 3.2. Мы будем называть такие иерархии классов распределенными (scattered), поскольку типы в списке типов распределены по разным корневым классам. В этом заключается сущность класса GenScatterHierarchy - он генерирует иерархию классов для пользователя, многократно конкретизируя шаблонный класс, предоставленный ему в качестве модели. Затем он собирает все сгенерированные классы в один, в данном случае - класс widgetlnfo. В результате наследования классы Holder<int>, Holder<string>, Holder<widget> и widgetlnfo имеют одну переменную-член value type для каждого типа, указанного в списке типов. На рис. 3.3 показана бинарная схема объекта класса widgetlnfo. Предполагается, что такие пустые классы, как GenScatterHiегагсЬу<МиПтуре, Holder>, игнорируются и не занимают места в составном объекте. Объекты класса Widgetinfo позволяют делать интересные вещи. Например, можно обратиться к объекту класса string, хранящемуся в объекте класса Widgelnfo, написав следующий код. widgetinfo obj; string name = (static cast<Holder<string>&>(obj)).value ; Явное приведение типов позволяет избежать неоднозначности имени value . В противном случае компилятор не сможет определить, на какой член val ue вы ссылаетесь.
GenScatterHierarchy <TYPELIST 2(string,Widget),Holder> Рис. 3.3. Схема распределения памяти для объекта класса Widgetinfo Это приведение типов выглядит ужасно, поэтому мы попытаемся облегчить работу с классом GenScatterHierarchy, снабдив его несколькими удобными функциями доступа. Например, было бы прекрасно иметь доступ к члену класса по его типу. Это довольно просто. класс FieldTraits описан в файле HierarchyGenerators.h template <class т, class н> typename Private::FieldTraits<H>::Rebind<T>::Result& Field(H& obj) return obj; Работа функции Field основана на неявном преобразовании производного типа в базовый. При вызове Field<widget>(obj) (где obj должен иметь тип Widgetinfo) компилятор распознает, что но1 der<Wi dget> - это базовый класс по отношению к классу widgetinfo, и просто вернет ссылку на эту часть составного объекта. Почему функция Field является частью пространства имен, а не функцией-членом? Потому что такой высокий уровень обобщенного программирования вынуждает очень осторожно обращаться с именами. Представьте, например, что в классе Unit определен символ с именем Field. Если бы в классе GenScatterHierarchy была функция-член Field, она бы была замаскирована функцией Field, являющейся членом класса Unit. Это вызвало бы массу недоразумений. У функции Field есть один недостаток: ее нельзя применять, если в списке типов есть дубликаты. Рассмотрим немного измененное определение класса Widgetinfo. typedef GenScatterHierarchy< TYPELiST 4(int, int, string, widget), value> widgetinfo; Теперь в классе widgetinfo есть два члена value , имеющих тип int. Если вызвать функцию Field<int> из объекта класса Widgetinfo, компилятор пожалуется на неоднозначность. Устранить эту неоднозначность нелегко, поскольку класс widgetinfo дважды наследует свойства класса Holder<int>, причем разными путями, как показано на рис. 3.4.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |