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

Метафункции высшего порядка (Каскады вложенных вызовов)

Функция высшего порядка - функция, которая воздействует на другую функцию. Из этого следует, что transform - метафункция высшего порядка: метафункция, которая воздействует на другую метафункцию (принимает обработчик с конкретными типами и применяет его к элементам последовательностей).

Разработаем новую метафункцию высшего порядка. Задача состоит в том, чтобы написать метафункцию, вызываемую дважды, необходимо поместить одну метафункцию в оператор вызова («()») другой и передать проивзольный аргумент х, результат работы вложенной метафункции будет передан в качестве аргумента внешней метафункции.

twice(f,x) := f(f(x))

Если f - класс метафункции, определение twice выглядит так – последовательность переопределений типов:

template <class F, class X>

struct twice

{

typedef typename F::template apply<X>::type once; // f(x)

typedef typename F::template apply<once>::type type; // f(f(x))

};

Можно применить метафункциональное продвижение (пересылку):

template <class F, class X>

struct twice

: F::template apply

<

typename F::template apply<X>::type

>

{};

Стандарт требует ключевое слово «template», когда используется зависимое имя, которое обращается к элементу шаблона «F::».

Чтобы не повторять в метафункции twice двойной вызов apply, создадим вспомогательную метафункцию для двойных вызовов:

template <class UnaryMetaFunctionClass, class Arg>

struct apply_helper

: UnaryMetaFunctionClass::template apply<Arg> //в apply содержится ::type

{};

Теперь можно записать twice так:

template <class F, class X>

struct twice : apply_helper<F, typename apply_helper<F, X>::type>{};

Пример использования: создадим класс метафункции для добавления опретора «*»:

struct add_pointer_f

{

template <class T>

struct apply : boost::add_pointer<T> {};

};

Теперь можно использовать twice и add_pointer_f для двойного добавления к типу оператора «*» - создание «указателя на указатель»:

BOOST_STATIC_ASSERT

((

boost::is_same<

twice<add_pointer_f, int>::type, int** //Двойное добавление «*» к типу int

>::value

));

Использование apply:

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

#include <boost/mpl/apply.hpp>

template <class F, class X>

struct twice

: mpl::apply<F, typename mpl::apply<F,X>::type> {};

В MPL реализация метафункции apply подобна apply_helper, но с двумя дополнительными возможностями:

  • В то время как apply_helper работает только с классами метафункций, первым аргументом для mpl::apply может быть любая лямбда метафукнция (включая объявленных с заполнителями (placeholders)).

  • В то время как apply_helper принимает только один дополнительный аргумент, к которому будет применен класс метафункции, mpl::apply может принимать любое число от ноля до пяти дополнительных аргументов(См. раздел Макроопределения MPL для описания того, как изменить максимальное количество аргументов для mpl::apply.):

// binary lambda expression applied to 2 additional arguments

boost::mpl::apply

<

mpl::plus<mpl::_1, mpl::_2>,

mpl::int_<6>,

mpl::int_<7>

>::type::value // == 13

Директива:

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

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