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

Пример:

template <class Seq>

struct my_reverse

: mpl::fold<

Seq,

typename mpl::clear<Seq>::type,

mpl::push_front<_,_>

>

{};

//+--------------------------------------------------------------------+

int main()

{

typedef mpl::vector<Char,Int,Float> t_list;

t_list::item0 obj;

obj.ch = 'a';

obj.func();

typedef my_reverse<t_list>::type rev_list;

rev_list::item0 r_obj;

r_obj.func();

return 0;

}

reverse_fold

Особенность работы mpl::fold: когда он используется с push_front, результат всегда выходит в обратном порядке. Поскольку списки (mpl::list) могут быть построены только с push_front, то крайне возникает потребность применять к результирующей последовательности дополнительно mpl::reverse, что крайне неэффективно, потому MPL также предоставляет метафункцию reverse_fold, которая обрабатывает элементы в обратном порядке.

Для последовательностей, который могут быть пройдены только в прямом направлении используется следующий подход: вместо действий с «головой» последовательности и сворачиванием «хвоста» через mpl::fold, выполняется mpl::fold с «хвостом», а затем действия с «головой»:

reverse_fold(Seq, Prev, BinaryOp) :=

if Seq is empty then:

Prev

else: // process the rest of the sequence

BinaryOp( // and combine with the first element

reverse_fold(tail(seq), Prev, BinaryOp),

head(seq)

)

Вместо обработки каждого элемента последовательности в процессе «раскрутки» рекурсии, обработка происходит наоборот, в процессе «сворачивания» рекурсии.

Можно вести обработку в обоих направлениях, что поддерживается метафункцией mpl::reverse_fold, которая принимает в качестве четвертого аргумента возможность выбора этапа, на котором должна вестись обработка: раскрутка/сворачивание рекурсии.

reverse_fold(Seq, Prev, OutOp, InOp = _1) :=

if Seq is empty then:

Prev

else:

OutOp( // Сворачивание рекурсии

reverse_fold( // Раскрутика рекурсии

tail(Seq),

InOp(Prev,head(Seq)), // just Prev by default

OutOp,

InOp),

head(Seq)

)

Такое обобщение позволяет максимально эффективно использовать рекурсивное поведение. По умолчанию используется операция InOp, которая просто возвращает свой ​​первый аргумент, что эквивалентно когда InOp не используется, то Prev просто передается рекурсивному вызову.

iter_fold

Вместо того, чтобы делать обход по элементам последовательности, мы можем перебирать значения итератора. Это полезно, например, если мы хотим вести обработку последовательного поддиапазона входной последовательности. Для этого используется iter_fold:

iter_fold(Seq, Prev, BinaryOp) :=

if Seq is empty then:

Prev

else: // combine the first position with Prev

iter_fold( // and process the rest recursively

tail(Seq)

, BinaryOp(Prev, begin(Seq))

, BinaryOp

)

Основное различие между fold и iter_fold в том, что вторым аргументом BinaryOp является итератор, а не элемент последовательности.

reverse_iter_fold

Также поддерживается полное обобщение reverse_iter_fold:

reverse_iter_fold(Seq, Prev, OutOp, InOp = _1) :=

if Seq is empty then:

Prev

else:

OutOp(

reverse_iter_fold(

tail(Seq),

InOp(Prev, begin(Seq)),

OutOp,

InOp),

begin(Seq)

)

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