Анимация
JavaScript
|
Главная Библионтека мого диапазона изменения индексов в ней запрещен менее строго и приводит не к порождению сообщения об ощибке на этапе компиляции, а к выдаче в качестве результата типа, заданного пользователем по умолчанию. Структура TypeAtNonStrict используется в обобщенной реализации обратного вызова, описанной в главе 5. Время индексированного доступа к элементам списка типов прямо пропорционально размеру списка. Для списка значений этот метод неэффективен (по этой причине в классе std::1ist не определена функция operator[]). Однако для списков типов время тратится на этапе компиляции и его объем не имеет большого значения. 3.7. Поиск элемента Как найти нужный тип в списке типов? Попробуем реализовать алгоритм indexof, вычисляющий индекс типа в списке. Если тип не найден, результатом будет некоторое фиксированное число, например -1. Этот алгоритм представляет собой классическую рекурсивную реализацию линейного поиска. indexOF Входные данные: список типов TList, тип т Результат: внутренняя статическая константа value Если список TList состоит из единственного типа NullType, то значение value равно -1. Иначе, если в голове списка TList находится тип т, то значение value равно 0. Иначе вычислить результат алгоритма IndexOf, применяя его к хвосту списка Tlist и типу т, и присвоить его переменной temp. Если значение temp равно -1, то значение value равно -1. Иначе значение value равно 1 плюс temp. Aлгopиtм indexOf относительно прост. Особое внимание уделяется передаче значение value ("тип не найден") в качестве результата. Последняя ветвь алгоритма (вычисление значения value в зависимости от значения temp) представляет собой операцию над числами и выполняется с помощью условного оператора ?:. Ниже приводится реализация алгоритма. template <class TList, class т> struct IndexOf; template <class T> struct lndexOF<NullType, T> enum { value = -1 }; template <class T, class Tail> struct lndexof<Typelist<T, Tail>, T> Ha самом деле при разработке больших проектов это не совсем так. Возможна ситуация, по крайней мере теоретически, когда сложные манипуляции со списками типов смогут существенно замедлить компиляцию программы. В любом случае программа, содержащая очень длинный список типов, либо очень долго выполняется (и тогда лучше смириться с долгой компиляцией), либо является слишком сложной (и тогда ее следует разработать заново). enum{ value = 0 }; template <class Head, class Tail, class T> struct indexOf<Typelist<Head, Tail>, т> private: enum { temp = lndexOf<Tai1, T>::value }; public: enum { value = temp == -1 ? -1 : 1 + temp }; 3.8. Добавление элемента Нам нужно иметь возможность добавлять в список типов новый тип или список типов. Поскольку модификация списка типов невозможна, будем выполнять "возврат по значению", создавая новый список типов, содержащий результат. Append Входные данные: список типов TList, тип или список типов т Результат: определение внутреннего типа Result Если список TList состоит из единственного типа NullType и параметр т является типом NullType, то класс Result является типом NullType. Иначе, если список TList состоит из единственного типа NullType и параметр т является отдельным типом (а не списком типов), то класс Result является списком, состоящим из единственного элемента т. Иначе, если список TList состоит из единственного типа NullType и параметр т является списком типов, то класс Result является типом т. Иначе, если список TList не состоит из единственного типа NullType, то класс Result является списком типов, головой которого является тип TLi St:: Head, а хвостом - результат добавления списка т к элементу TLi St: :Tai 1 в качестве хвоста. Этот алгоритм естественно выражается следующим кодом, template <class TList, class т> struct Append; emplate <> struct Append<NullType, NullType> typedef NullType Result; emplate <class т> struct Append<NullType, T> typedef TYPELIST 1(T) Result; emplate <class Head, class Tail> truct Append<NunType, Typel ist<Head, Tail> > typedef Typelist<Head, Tail> Result; Глава 3. Списки типов 79 template <class Head, class Tail, class т> struct Append<Typelist<Head, Tail>, т> { typedef Typelist<Head, typename Append<Tail, т>::Result> Result; Обратите внимание на то, как последняя частично специализированная версия структуры Append рекурсивно конкретизирует шаблон Append, передавая ему хвост списка и добавляемый тип. Теперь для типов и списков типов определена унифицированная операция Append. Например, приведенный ниже оператор определяет список, состоящий из всех числовых типов со знаком, предусмотренных в языке С++. typedef Append<Signedintegrals, TYPELIST 3(float, double, long double)>::Result SignedTypes; 3.9. Удаление элемента Рассмотрим теперь обратную операцию - удаление элемента из списка типов. У нас есть две возможности: удалить только первое вхождение или удалять все вхождения данного типа в списке. Изучим только первый вариант. Erase Входные данные: список типов TList, типт Результат: определение внутреннего типа Result Если список TList состоит из единственного типа NullType, то класс Result является типом NullType. Иначе, если тип т совпадает с типом TLi st:: Head, то класс Result является типом TList: :Tail. Иначе класс Result является списком типов, голова которого является типом TList: :Head, а хвостом - результат применения алгоритма Erase к хвосту TLi st: Tai 1 с параметром т. Вот как выглядит этот алгоритм на языке С++. template <class TList, class т> struct Erase; template <class т> Специализация 1 struct Erase<NullType, т> typedef NullType Result; template <class т, class Tail> Специализация 2 struct Erase<Type1ist<T, Tail>, т> typedef Tail Result; template <class Head, class Tail, class т > специализация 3 80 Часть I. Методы 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 |