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

Упрощение 1

Такое повторение фактически дает подсказку относительно того, как мы могли бы улучшить положение вещей. Мы ищем в последовательности элементов упорядоченной по размерам, сравнивая размер каждого с заданным значением и возвращаем размер найденного. Нас не интересует последовательность самих элементов: мы заботимся только об их размерах.

Так, нужно сделать из последовательности типов соответствующую последовательность размеров и вести поиск в ней, это позволяет использовать предикат c однородным сравнением элементов:

template<class Seq, class MinSize>

struct padded_size

: mpl::deref<

typename mpl::lower_bound<

typename mpl::transform<Seq, mpl::sizeof_<_>>::type, //последовательность размеров

MinSize,

mpl::less<_,_> //однородное сравнение

>::type

>

{};

К тому же, в метафункции mpl::lower_bound по умолчанию используется предикат mpl::less<_, _>, следовательно можно упростить запись до:

template<class Seq, class MinSize>

struct padded_size

: mpl::deref<

typename mpl::lower_bound<

typename mpl::transform<Seq, mpl::sizeof_<_>>::type,

MinSize

>::type

>

{};

Так, в первой версии, сложность последовательного расчета размера типа составляла O(log N) – экспоненциально возрастала с количеством. Во второй версии, сначала расчитывались размеры элементов всей последовательности, после чего, она передавалась в метафункцию mpl::lower_bound.

Проблема: плохая эффективность.

Упрощение 2 (создание просмотра)

Можно объединить лучшее, что есть в двух версиях, создав последовательность просмотра, что позволит определять размеры с помощью ленивого вызова transform_view:

template<class Seq, class MinSize>

struct first_size_larger_than

: mpl::deref<

typename mpl::lower_bound<

mpl::transform_view<Seq, mpl::sizeof_<_>>,

MinSize

>::type

>

{};

Transform_view <S, P> является последовательностью просмотра, элементы которой идентичны элементам transform <S, P>, но с двумя важными различиями:

  • Элементы вычисляются только «по требованию» - ленивая последовательность.

  • Каждый итератор последовательности просмотра является адаптером для одного или нескольких базовых итераторов (от базовых последовательностей), для обращения к значениям каждого из базовых итераторов (соответствующей позиции в S), используется вложенный элемент «::base».

zip_view

Объединение множественных (мульти-) последовательностей

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

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

Алгоритм zip_view преобразовывает последовательность N-ого количества входных последовательностей в последовательность последовательностей и упорядочивает элементы. Так, если

S [s1, s2, s3...], T [t1, t2, t3...], и U [u1, u2, u3...],

то элементы zip_view <vector <S, T, U>> будут иметь вид

[[s1, t1, u1...], [s2, t2, u2...], [s3, t3, u3...]...].

Например, поэлементная сумма трех векторов могла бы быть записана:

mpl::transform_view<

mpl::zip_view<mpl::vector<V1,V2,V3>>,

mpl::plus<

mpl::at<_, mpl::int_<0>>,

mpl::at<_, mpl::int_<1>>,

mpl::at<_, mpl::int_<2>>

>

>

Это не слишком плохо, но, распаковка векторных элементов с mpl::at является громоздкой и неудобной. Код можно улучшить, используя MPL обертку unpack_args, которая преобразовывает лямбда-выражение с N-ым количеством аргументов наподобии mpl::plus<_, _, _> в унарное лямбда-выражение.

Когда к последовательности из N элементов применяется:

mpl::unpack_args <лямбда-выражение>

то извлекается каждый из элементов последовательности и поочередно передается параметру лямбда-выражение.

Следующая эквивалентная перезапись поэлементной суммы использует unpack_args, чтобы достигнуть существенного улучшения удобочитаемости:

mpl::transform_view<

mpl::zip_view<mpl::vector<V1,V2,V3>>,

mpl::unpack_args<mpl::plus<_,_,_>>

>

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