Анимация
JavaScript
|
Главная Библионтека struct Erase<Typelist<Head, Tail>, T> { typedef Typelist<Head, typename Erase<Tail, T>::Result> Result; Как и для класса TypeAt, для этого шаблонного класса не предусмотрен вариант по умолчанию. Это означает, что класс Erase можно конкретизировать только определенными типами. Например, выражение Erase<double, int> вызовет ошибку компиляции, поскольку для него не сушествует ни одного соответствия. Кроме того, необходимо, чтобы первый параметр шаблонного класса Erase был списком типов. Используя определение класса SingedTypes, можно записать следующее. класс SomeSignedTypes содержит эквивалент класса TYPELiST 6Csigned char, short int, int, long int, double, long double) typedef Erase<signedTypes, float>::Result SomeSignedTypes; Рассмотрим рекурсивный алгоритм удаления элементов. Шаблон EraseAll удаляет все вхождения типа в список типов. Его реализация аналогична классу Erase, за одним исключением. При обнаружении типа, подлежащего удалению, алгоритм не останавливается, а продолжает искать и удалять соответствующие элементы из хвоста списка, рекурсивно применяя самого себя. template <class TList, class т> struct EraseAll; template <class T> struct EraseAll<NullType, T> typedef NullType Result; template <class T, clas Tail> struct EraseAll<Typelist<T, Tail>, T> проходит вниз по списку, удаляя заданный тип typedef typename EraseAll<Tail, T>::Result Result; template <class Head, class Tail, class T> struct EraseAll<Typelist<Head, Tail>, T> { проходит no списку, удаляя заданный тип typedef Typelist<Head typename EraseAll<Tail, T>::Result> Result; 3.10. Удаление дубликатов Важной операцией над списками типов является удаление дубликатов. Ее цель - трансформировать список типов так, чтобы каждый тип в списке встречался лишь один раз. Например, из списка TYPELIST 6(Widget, Button, widget, TextField, ScrollBar, Button) нужно получить список TYPELIST 6(widget, Button, TextField, ScrollBar) Эта процедура немного сложнее, однако, как легко догадаться, нам поможет класс Erase. NoDuplicates Входные данные: список типов TList Результат: определение внутреннего типа Result Если список TList состоит из единственного типа NullType, то класс Result является типом NullType. Иначе применить алгоритм NoDuplicates к списку TList: :Tail, получив временный список Ll; применить алгоритм Erase к списку TList: :Head, получив в результате список L2. Класс Result - это список типов, голова которого является списком TList: :Head, а хвост - списком L2. Вот как этот алгоритм переводится на язык С++, template <class TList> struct NoDuplicates; template <> struct NoDuplicates<NullType> { typedef NullType Result; template <class Head, class Tail> struct NoDuplicates< Typelist<Head, Tail> > private: typedef typename NoDuplicates<Tail>::Result Ll; typedef typename Erase<Ll, Head>::Result L2; public: typedef Typelist<Head, l2> Result; Почему мы воспользовались алгоритмом Erase, имея в своем распоряжении алгоритм EraseAll? Ведь мы хотим удалить все дубликаты данного типа, не правда ли? Ответ заключается в том, что алгоритм Erase применяется после рекурсивного вызова алгоритма NoDuplicates. Это означает, что мы удаляем из списка тип, у которого уже нет дубликата, поэтому в списке останется по крайней мере один экземпляр данного типа. Это довольно интересный пример рекурсивного программирования. 3.11. Замена элемента Иногда вместо удаления нужно заменить какой-то элемент в списке типов. Как мы увидим в разделе 3.12, замена одного типа другим представляет собой важную строительную конструкцию для многих сложных идиом. Допустим, что нам нужно заменить тип т типом и в списке типов TList. Replace Входные данные: список типов TList, тип т (подлежащий замене) и тип и (замена) Результат: определение внутреннего типа Result Если список TList состоит из единственного типа NullType, то класс Result является типом NullType. Иначе, если голова списка TList является типом т, то класс Result представляет собой список типов, у которого голова является типом и, а хвостом служит список TList::Tail. Иначе класс Result представляет собой список типов, у которого голова является списком TList: :Head, а хвостом служит результат применения алгоритма Replace к списку т1 i St и па15аметрам т и U. Вот как выглядит код этого рекурсивного алгоритма. template <class TList, class т, class U> struct Replace; template <class T, class U> struct Replace<NullType, т, u> { typedef NullType Result; template <class T, class Tail, class U> struct Replace<Typelist<T, Tail>, T, u> { typedef Typelist<u, Tail> Result; template <class Head, class Tail, class т, class u> struct Replace<Typelist<Head, Tail>, T, u> typedef Typelist<Head, typename Replace<Tail, T, u>::Result Result; Алгоритм ReplaceAll легко получить, изменив вторую специализацию так, чтобы в ней алгоритм рекурсивно применялся к списку Tai 1. 3.12. Частично упорядоченные списки типов Допустим, нам нужно упорядочить список типов по отношению наследования. Например, мы бы хотели, чтобы производные типы предшествовали базовым. Пусть мы имеем иерархию классов, изображенную на рис. 3.1. Предположим, что у нас есть список типов TYPELIST 4(widget, ScrollBar, Button, GraphicButton) Наша задача - преобразовать его следующим образом: TYPELIST 4(Scrollваг, GraphicButton, Button, widget) Следовательно, нам нужно переставить производные классы вперед, оставив порядок следования классов одинакового уровня (sibling) прежним. На первый взгляд эта задача кажется надуманной, однако она имеет большое практическое значение. Просмотр упорядоченного списка типов, в котором производные типы стоят впереди, соответствует обходу иерархии классов снизу вверх. Ме- 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 [ 22 ] 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |