Зачитался я тут книгой Александреску «Современное проектирование на С++: Обобщенное программирование и прикладные шаблоны проектирования».
Познакомившись со списками типов и алгоритмами для работы с ними, понял, что списки типов по Александреску совсем никакие не списки, а бинарные деревья типов. После чего я решил закрепить материал и запрограммировать какой-нибудь простой алгоритм на деревьях типов, например, поиск в глубину.
Итак, деревья типов отличаются от списков типов только названием:
Познакомившись со списками типов и алгоритмами для работы с ними, понял, что списки типов по Александреску совсем никакие не списки, а бинарные деревья типов. После чего я решил закрепить материал и запрограммировать какой-нибудь простой алгоритм на деревьях типов, например, поиск в глубину.
Итак, деревья типов отличаются от списков типов только названием:
template <class T, class U> struct TypeTree { typedef T Left; typedef U Right; };
Чтобы было понятнее приведу пример:
TypeTree<TypeTree<int, double>, TypeTree<float, TypeTree<char, long> > >
На картинке это буде выглядеть примерно так:
Заодно будем нумеровать узлы так, что если родитель имеет номер n, то левый потомок имеет номер 2*n, а правый --- 2*n + 1. Корневая вершина имеет номер 1.
Теперь об алгоритме поиска типа в дереве типов. Если в дереве типов нет искомого типа, то результатом будет 0, иначе номер искомого типа.
Шаблонный класс DFS в качестве шаблонных параметров принимает дерево типов и искомый тип. Код алгоритма:
template <class TTree, class T> struct DFS; // Дерево состоит из одной вершины, которая соответствует искомому типу template <class T> struct DFS<T, T> { enum { value = 1 }; }; // Дерево состоит из одной вершины, которая не соответствует искомому типу template <class T, class U> struct DFS { enum { value = 0 }; }; // Дерево со многими вершинами template <class Left, class Right, class T> struct DFS<TypeTree<Left, Right>, T> { // Запускаем алгоритм поиска в глубину для левой и правой веток enum { value = DFS_<Left, T, 2>::value + DFS_<Right, T, 3>::value }; };Класс DFS_ имеет три шаблонных параметра --- два как у класса DFS и целое без знака. Целое число показывает какую вершину мы рассматриваем в данный момент. Код:
template <class TTree, class T, unsigned int i> struct DFS_; // Листовая вершина с искомым типом template <class T, unsigned int i> struct DFS_<T, T, i> { enum { value = i }; }; // Листовая вершина с типом отличным от искомого template <class U, class T, unsigned int i> struct DFS_ { enum { value = 0 }; }; // Не листовая вершина template <class Left, class Right, class T, unsigned int i> struct DFS_<TypeTree<Left, Right>, T, i> { enum { value = DFS_<Left, T, 2*i>::value + DFS_<Right, T, 2*i + 1>::value }; };
Код, написанный ниже, напечатает на экране число 14.
std::cout << DFS< TypeTree<TypeTree<int, double>, TypeTree<float, TypeTree<char, long> > >, char >::value << std::endl;
Вот и все. :)
Из недостатков можно отметить:
- Будет не очень информативный результат, если в дереве есть два одинаковых типа.
- Не обрабатывается NullType, который мог бы быть индикатором «сухих листьев» (отсутствующих братьев).
http://habrahabr.ru/post/220217/
ОтветитьУдалить