Списки типів Нікітін Олексій
Навіщо потрібні списки типів? Розглянемо шаблон Abstract Factory. class WidgetFactory { public: virtual Window* createWindow() = 0; virtual Button* createButton() = 0; virtual ScrollBar* createScrollBar() = 0; }
1) Така фабрика може створювати лише об’єкти типу Widget, Button, ScrollBar 2) Функціями-членами класу WidgetFactory неможливо вільно маніпулювати. Розглянемо такий код template T* makeRedWidget(WidgetFactory& factory) { T* pw = factory.createT();//неможливо pw->setColor(RED); return pw; }
Хотілося б мати Фабрику, якій можна вказати – які саме об’єкти вона повинна створювати. Наприклад typedef AbstractFactory WidgetFactory. Але шаблони не можуть мати змінну кількість параметрів.
template T* makeRedWidget(WidgetFactory& factory) { T* pw = factory.create (); pw->setColor(RED); return pw; } Але в С++ неможливо створити шаблонну віртуальну функцію.
Визначення списків типів Список, який складається з двох типів. template struct Typelist { typedef T head; typedef U tail; };
Список, який складається з трьох типів. typedef Typelist > Charlist; Також потрібен нульовий тип списку, який не містить жодного типу, нехай це буде класс NullType. Також нехай NullType буде маркером кінця списку.
Список, який містить один тип typedef Typelist OneTypeList; Два типи typedef Typelist > TwoTypeList;
За допомогою макросів можна покращити зовнішній вигляд визначення списків типів. #define TYPELIST_1(T1) Typelist #define TYPELIST_2(T1, T2) Typelist #define TYPELIST_3(T1, T2, T3) Typelist …..
Визначення списку з чотирьох типів typedef TYPELIST_4(char, short, int, long int) MyTypeList; еквівалентно Typelist<char, Typelist<short, Typelist<int, Typelist > > >
Обрахування дліни списку template struct Length; template <> struct Length { enum { value = 0 }; } template struct Length > { enum { value = 1 + Length ::value }; }
Індексований доступ template struct TypeAt; Надаємо список типів TList та index. Отримуємо оголошення типу, який стоїть в списку за певним індексом.
template struct TypeAt, 0> { typedef Head Result; } template struct TypeAt, i> { typedef typename TypeAt ::Result Result; };
Пошук індекса типа template struct IndexOf; template struct IndexOf { enum { value = -1; }; }
template struct IndexOf, T> { enum { value = 0 }; }; template struct IndexOf, T> { private: enum { temp = IndexOf ::value }; public: enum { value = (temp == -1 ? -1 : 1 + temp) }; };
Додавання елемента template struct Append; template <> struct Append { typedef NullType Result; }; template struct Append { typedef TYPELIST_1(T) Result; };
template struct Append > { typedef Typelist Result; } template struct Append, T> { typedef Typelist ::Result> Result; };
Видалення елемента template struct Erase; template struct Erase { typedef NullType Result; }
template struct Erase, T> { typedef Tail Result; //typedef typename EraseAll ::Result result; }; template struct Erase, T> { typedef Typelist<Head, typename Erase ::Result> Result; };
Видалення дублікатів template struct NoDuplicates; template <> struct NoDuplicates { typedef NullType Result; }; template struct NoDuplicates > { private: typedef typename NoDuplicates ::Result L1; typedef typename Erase ::Result L2; public: typedef Typelist Result; };
Заміна елемента template struct Replace; template struct Replace { typedef NullType Result; };
template struct Replace, T, U> { typedef Typelist Result; //typedef Typelist<U, typename Replace ::Result > Result; }; template struct Replace, T, U> { typedef Typelist<Head, typename Replace ::Result> Result; };
Частково впорядковані списки типів Потрібно в певному списку переставити типи так, щоб нащадки були попереду. Еквівалентно обходу ієрархії класів знизу уверх.
Потрібні: #define SUPERSUBCLASS(T, U) SuperSubclass ::value який має значення True, якщо класс U є нащадком класу T. Select – використовує отримане boolean значення. template struct Select { typedef T Result; }; template struct Select { typedef U Result; };
MostDerived Пошук нащадка самого нижнього рівня template struct MostDerived; template struct MostDerived { typedef T Result; };
template struct MostDerived, T> { private: typedef typename MostDerived ::Result Candidate; public: typedef typename Select <SUPERSUBCLASS(Candidate, Head), Head, Candidate>::Result Result; };
DerivedToFront template struct DerivedToFront; template<> struct DerivedToFront { typedef NullType Result; };
template struct DerivedToFront > { private: typedef typename MostDerived ::Result TheMostDerived; typedef typename Replace ::Result Temp; typedef typename DerivedToFront ::Result L; public: typedef Typelist Result; };
Генерація розподілених ієрархій template struct Unit { T value_; } template class Unit> class GenScatterHierarchy; Процес конкретизації класса GenScatterHierarchy закінчується спадкуванням класу Unit, конкретизованого кожним типом зі списку типів
typedef GenScatterHierarchy WidgetInfo; Порожній список: template class Unit> class GenScatterHierarchy { };
Атомарний тип ( не список типів) template class Unit> class GenScatterHierarchy : public Unit { typedef Unit LeftBase; };
Список типів: template class Unit> class GenScatterHierarchy, Unit> : public GenScatterHierarchy, public GenScatterHierarchy { public: typedef GenScatterHierarchy LeftBase; typedef GenScatterHierarchy RightBase; };
Звертання до атрибуту value_ класу Holder через екземпляр класу WidgetInfo. WidgetInfo obj; string name = (static_cast &>(obj)).value_;
Генерація лінійних ієрархій template class EventHandler { public: virtual void OnEvent(const T&, int eventId) = 0; virtual void ~EventHandler() { } };
typedef GenScatterHierarchy < TYPELIST_3(Window, Button, ScrollBar), EventHandler > WidgetEventHandler; Через множинне спадкування клас WidgetEventHandler містить три вказівника на віртуальні таблиці, по одній для кожної конкретизації класу EventHandler.
У випадку звичайного спадкування клас WidgetEventHandler може мати лише один вказівник на віртуальну таблицю
Рішення template < class TList, template class Unit, class Root = EmptyType > class GenLinearHierarchy;
template < class T1, class T2, template class Unit, class Root > class GenLinearHierarchy, Unit, Root> : public Unit > { };
template < class T, template class Unit, class Root > class GenLinearHierarchy : public Unit { };
Приклад використання template class EventHandler: public Base { public: virtual void OnEvent(T& obj, int eventId); }; typedef GenLinearHierarchy < TYPELIST_3(Window, Button, ScrollBar), EventHandler > MyEventHandler.
Дякую за увагу