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

Пример 1:

Вставка, которая строит новый вектор может выглядеть так:

mpl::inserter<mpl::vector<>, mpl::push_back<_,_>>

где mpl::inserter определяется как:

template <class State, class Operation>

struct inserter

{

typedef State state;

typedef Operation operation;

};

Работа вставки основана на операциях подобных push_back и push_front с подобнымие именами и назначением: back_inserter и front_inserter.

mpl::back_inserter<mpl::vector<>>

Пример 2:

Использование вставок в STL для алгоритма std::copy:

std::vector<any> v; // start with empty vector

std::copy(start, finish, std::back_inserter(v));

Версия mpl::copy принимает входящую последовательность вместо пары итераторов как в STL версии:

typedef mpl::copy

<

mpl::list<A, B, C>,

mpl::back_inserter<mpl::vector<>>

>::type result_vec;

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

typedef

mpl::push_back< // >----------------+

// |

mpl::push_back< // >--------------+ |

// | |

mpl::push_back< // >------------+ | |

mpl::vector<> // | | |

, A // | | |

>::type // first step <-+ | |

, B // | |

>::type // second step <--+ |

, C // |

>::type // third step <-----+

result_vec;

MPL поддерживает вставки по умолчанию для всех алгоритмов, создающих последовательностями (именно поэтому мы смогли использовать mpl::transform, без явного указания вставки.).

Пример 3:

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

typedef mpl::vector<

mpl::vector_c<int, 1, 2, 3>,

mpl::vector_c<int, 4, 5, 6>,

mpl::vector_c<int, 7, 8, 9>

> S;

typedef mpl::transform<

S, // input sequence

mpl::front<_>, // transformation selects front element (вернет 1 элемент)

mpl::inserter<

mpl::int_<0>, // result starts with 0

mpl::plus<_,_> // and adds each output element

>

>::type sum; // 0 + 1 + 4 + 7 == 12

Без вставки, transform будет строить вектор, состоящий из первоначальных элементов каждой последовательности в S; при использовании вставки, эти начальные элементы передаются в mpl::plus<_,_>, начиная со значения mpl::int_<0>.

Фундамент алгоритмов

В основе работы алгоритмов подобных back_inserter лежит паттерн «сворачивания» элементов входящей последовательности в результирующую.

Данный паттерн является ядром обработки всех последовательностей в функциональной среде и реализовывается метафункциями «*_fold».

Является фундаментальной функциональной абстракцией, которая повторяет применение бинарной функции к элементам и последовательности и «накапливает» результирующее значение, используя результат функции на каждом шаге, как дополнительное значение для следующего шага. STL содержит подобную абстракцию под названием accumulate.

MPL обобщает реализацю fold двумя способами: для работы с элементами последовательности или их значениями, с помощью (iter_fold) а таже, обеспечивая двунаправленный обхода (reverse_ [iter_] fold).

fold

Псевдокод:

fold(Seq, Prev, BinaryOp) :=

if Seq is empty then:

Prev

else: // combine the first element with Prev

fold( // and process the rest recursively

tail(Seq), // оставить хвост последовательности

BinaryOp(Prev, head(Seq)), // обработка Prev и головы

BinaryOp

)

Prev, вероятно, следует назвать InitialType. На каждом этапе обработки, кроме первого, Prev является результатом предыдущего шага обработки.

Можно создать много других, более сложных последовательностей обхода алгоритмов используя логику mpl::fold для раскрутки последовательности (достаточно выполнить наследование).

Например, можно разворачивать любые последовательности, поддерживающие расширения front_*:

template <class Seq>

struct reverse

: mpl::fold<

Seq,

typename mpl::clear<Seq>::type, // initial type - чистая последовательность равной длины

mpl::push_front<_,_> // binary operation: push_front(ячейка чистой Seq, элемент Seq)

>

{};

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