Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
template_metaprogramming_ru.docx
Скачиваний:
12
Добавлен:
01.07.2025
Размер:
774 Кб
Скачать
☆

Наследование

Как правило, непронумерованная форма любой последовательности получена из соответствующей пронумерованной формы, или имеет общий базовый класс, который обеспечивает выполнение последовательности.

Например, mpl::vector мог бы быть определен так:

namespace boost {

namespace mpl {

struct void_; // "no argument" marker

// primary template declaration

template <class T0 = void_, class T1 = void_, etc....>

struct vector;

// specializations

template<>

struct vector<> : vector0<> {};

template<class T0>

struct vector<T0> : vector1<T0> {};

template<class T0, class T1>

struct vector<T0,T1> : vector2<T0,T1> {};

template<class T0, class T1, class T2>

struct vector<T0,T1,T2> : vector3<T0,T1,T2> {};

//etc...

}

}

Интегральные обертки последовательности так же являются производными из эквивалентных основных последовательностей типа.

Все встроенные последовательности MPL разработаны так, чтобы почти любой подкласс функционировал как эквивалентная последовательность типа.

Наследование - сильный способ обеспечить новый интерфейс, или только новое имя, существующей семье последовательностей.

Например, библиотека Boost Python обеспечивает следующую последовательность типа:

namespace boost {

namespace python {

template <class T0 = mpl::void_, ... class T4 = mpl::void_>

struct bases : mpl::vector<T0, T1, T2, T3, T4> {};

}

}

Так, с поомщью наследования можно создавать свои последовательности:

struct signed_integers

: mpl::vector<signed char, short, int, long> {};

На некоторых компиляторах, используя signed_integers вместо основного вектора может резко улучшить эффективность метапрограммы.

Создание последовательности

Причиной создания собственных последовательностей обычно является вопрос эффективности и оптимизации приложения. В то время как последовательности MPL хорошо оптимизированы для использования общего назначения, а специализированная версия может дать прирост скорости.

Для этого примера напишем последовательность произвольного доступа ограниченного размера, эта реализация будет очень близкой к реализации mpl::vector для тех компиляторов, которые не поддерживают конструкцию typeof.

Реализация:

Выбрать представление (внутреннее состояние класса), для этого требуется 3 элемента (ограничимся этим количеством) для трех типов, которые оно может содержать в последовательности:

struct none {}; // tag type to denote no element

template <class T0 = none, class T1 = none, class T2 = none>

struct tiny

{

typedef tiny type;

typedef T0 t0;

typedef T1 t1;

typedef T2 t2;

//...

};

Вложенным типом будет тип самой последовательности: «самовозвращающаяся метафункция». Все последовательности MPL делают что-то подобное – очень удобное решение. Например: если необходимо возвратить последовательность из какой-либо метафункции, то можно просто выполнить операцию наследования конкретной последовательности и продвинуть ее внутренний элемент «::type». Кроме того, когда одна ветвь в eval_if (один операнд) должна возвращать последовательность, то не нужно создавать дополнительную оберктку mpl::identity для него, т.о., можно делать выбор более простым способом(S - наша последовательность):

// pop the front element off S, unless it is empty

typedef mpl::eval_if<

mpl::empty<S>

, mpl::identity<S>

, mpl::pop_front<S>

>::type r1;

// likewise

typedef mpl::eval_if<

mpl::empty<S>

, S // when invoked, S returns S

, mpl::pop_front<S>

>::type r2;

Вложенные синонимы элементов последовательности: t0, t1, t2, позволяют удобно организовывать взаимодействие с данной последовательностью:

template <class Tiny>

struct manipulate_tiny;

template <class T0, class T1, class T2>

struct manipulate_tiny<tiny<T0, T1, T2>>

{

// T0 is known

};

Так, вложенные типы, позволяют упрощать код.

template <class Tiny>

struct manipulate_tiny

{

// what's T0?

typedef typename Tiny::t0 t0;

};

Пока типами элементов является структура none (маркер отсутствия элемента), такая обертка еще не явялется последовательностью, хоть и предоставляет удобный интерфейс для проведения до трех элементов.

Одно из оснонвых требований к последовательности - возврат итератора, для работы метафункция mpl::begin, mpl::end, потому необходимо добавить итератор в представление. Поскольку итератор произвольного доступа может перемещаться в обоих направлениях, то он будет иметь доступ ко всем элементам последовательности. Самый простой способ реализовать это, является внедрение всей последовательности в сам итератор. Такие внеднерения характерны для MPL итераторов, которым передается вся иличасть последовательности, которую они обойти(итераторам для контейнеров типа mpl::list необходимо передавать лишь оставшуюся часть списка –доступную часть последовательности ).

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]