- •Вычисления значений
- •Пример:
- •Вычисления типов
- •Преимущества мета подхода:
- •Польза использования mpl:
- •Числовая метафункция
- •Свойства
- •Метаданные
- •Специализация
- •Первичный шаблон:
- •Инстанцирование:
- •Метафункции
- •Полиморфизм
- •Возможности свойств:
- •Организация свойств в Boost:
- •Пример:
- •Типовые ассоциации
- •Альтернатива:
- •Метафункции Продвижение (пересылка) метафункций
- •Класс метафункции
- •Формат:
- •Числовые
- •Пример:
- •Нульарные
- •Метрический анализ (Анализ размерностей)
- •Метрики
- •Величины
- •Сложение и вычитание
- •Умножение
- •Класс метафункции
- •Деление
- •Пример:
- •Метафункции высшего порядка (Каскады вложенных вызовов)
- •Использование apply:
- •Заполнители
- •Безымянный заполнитель:
- •Определение выражений с заполнителями
- •Лямбда (Лямбда метафункции/выражения)
- •Частичное приложение метафункции
- •Лямбда и Шаблоны Неметафункции
- •Обертки
- •Выбор типа
- •Ленивый Выбор Типа
- •Логические Операторы
- •Целочисленные обертки
- •Составные Операторы
- •Операторы с булевым значением:
- •Операторы для сравнения значений:
- •Операторы для интегральных значений:
- •Побитовые операторы:
- •Арифметические операторы:
- •Целочисленная «стенография»
- •Интегральные последовательности
- •Формат:
- •Последовательности
- •Концепции
- •Итераторы
- •Двунаправленные
- •Произвольные
- •Последовательности
- •Двунаправленные
- •Произвольные
- •Расширенные
- •Ассоциативные
- •Требования
- •Расширения
- •Расширенные ассоциативные последовательности
- •Алгоритмы и последовательности
- •Итераторы
- •Равенство
- •Операции Внутренние операции с последовательностей
- •Наследование
- •Создание последовательности
- •Реализация:
- •Создание итератора
- •Преимущества полной специализации перед частичной:
- •Добавление расширения
- •Алгоритмы
- •Абстракция:
- •Stl алгоритмы
- •Детали правильного использования stl:
- •Mpl алгоритмы
- •Различия stl и mpl алгоритмов:
- •Пример:
- •Вставки
- •Пример 1:
- •Пример 2:
- •Пример 3:
- •Фундамент алгоритмов
- •Пример:
- •Запрашиваемые алгоритмы
- •Последовательности (Алгоритмы, создающие последовательности)
- •Синонимы функциональных алгоритмов:
- •Создание алгоритма
- •Итераторы «Просмотр» и итераторы-адаптеры
- •Концепция просмотра
- •Применение просмотра Сравнения значений элементов последовательности:
- •Объединение множественных (мульти-) последовательностей
- •Упрощение 1
- •Упрощение 2 (создание просмотра)
- •Уход от ненужного вычисления
- •Выборочная обработка элемента
- •Итератор-адаптер
- •Создание просмотра
- •Реализация итератора-адаптера для zip_view.
- •Диагностика
- •Отладка ошибок
- •Трассировка инстанцирования
- •Исправленный пример:
- •Форматы сообщений об ошибках
- •Блок «with»
- •Устранение параметров шаблона по умолчанию
- •Глубокий typedef
- •Инструменты
- •Несколько компиляторов
- •(Статические Утверждения)
- •Формат:
- •Формат:
- •Индивидуальные сообщения утверждений
- •Настройка предиката:
- •(Генерирование встроенных сообщений)
- •Формат:
- •Выбор стратегии:
- •Тип печати
- •Кросс этапность компиляции/выполнения
- •Печать типов:
- •Тип посещения:
- •Выбор реализаций
- •Специализация шаблонов классов
- •Тег диспетчеризации
- •Выбор структуры
- •Композиция классов
- •Указатели на функцию
- •Ослабление типизации
- •Пример:
- •Обобщение:
- •Динамический полиморфизм
- •Автоматизация
- •Сохранение интерфейса
- •Рекуррентный шаблон
- •Формат:
- •Генерирование функций
- •Управление разрешением перегрузки
- •Явное управление множеством перегрузки
- •Документация mpl Последовательности
- •Концепции
- •(Прямая последовательность)
- •(Двунаправленная Последовательность)
- •(Последовательность произвольного доступа)
- •(Расширенная последовательность)
- •(Расширенная последовательность начала)
- •(Расширенная последовательность конца)
- •(Ассоциативная последовательность)
- •(Расширенная ассоциативная последовательность)
- •(Обертка интегральной последовательности )
- •(Переменная последовательность)
- •Представления
- •Метафункции (Внутренние)
- •Итераторы
- •Концепции
- •(Прямой итератор)
- •(Двунаправленный итератор)
- •(Итератор произвольного доступа)
- •Метафункции
- •Алгоритмы
- •Концепции
- •(Инсертер: механизм вставок)
- •Инсертеры (инсертер: механизм вставок)
- •Итеративные алгоритмы
- •Запрашиваемые алгоритмы
- •Преобразования
- •Метафункции
- •Концепции Метафункция
- •Метафункциональный класс
- •Лямбда выражения
- •Заполнители
- •Тэг диспетчеризированные метафункции
- •Числовые метафункции
- •Тривиальные метафункции
Лямбда и Шаблоны Неметафункции
MPL использует специальное правило, чтобы облегчить объединение обычных шаблонов в метапрограммы: после того, как все заполнители были заменены фактическими аргументами, если у получившейся специализации шаблона X нет вложенного «::type», результат лямбды является только X.
Например, mpl::apply<vector<_>, T> является всегда только vector<T>. Если бы не это поведение мы должны были бы создавать тривиальные метафункции для обеспечения обычных специализаций шаблона в лямбда выражениях:
// trivial std::vector generator
template<class U>
struct make_vector { typedef std::vector<U> type; };
typedef mpl::apply<make_vector<_>, T>::type vector_of_t;
Вместо этого достаточно написать лишь 1 строку:
typedef mpl::apply<std::vector<_>, T>::type vector_of_t;
Обертки
(Wrappers)
Bool_
Тип bool не только самый простой составной тип, но также и один из самых полезных. Большинство свойств имеют тип bool. MPL реализует обертку для типа bool следующим образом:
template< bool x > struct bool_
{
static bool const value = x; // 1
typedef bool_<x> type; // 2
typedef bool value_type; // 3
operator bool() const { return x; } // 4
};
Разбор:
Каждая обертка для целочисленных констант содержит элемент «::value».
Каждая обертка – нульарная метафункция, которая возвращает саму себя. Причина такого архитектурного решения: позволяет реализовать «ленивые» вызовые метафункций в выражениях (не осуществлять инстацнирование шаблона там, где в нем нет необходимости).
Элемент «::value_type» указывает на тип элемента «::value».
Каждый обертка bool _<x> способна неявно преобразовываться к типу bool.
Библиотека также поставляет два удобных typedef’а:
typedef bool_<false> false_;
typedef bool_<true> true_;
Выбор типа
В большинстве случаем выбор типа происходит во время компиляции, с помощью механизхма специализаций шаблона класса: так, для заврешения рекурсивных алгоритмов используется специализация для нуля, подобный подход применим для деспетчиризации поведения, например: iter_swap_impl, чтобы выбрать одну из двух реализаций в теле iter_swap:
iter_swap_impl<use_swap>::do_it(*i1,*i2);
MPL предоставляет универсальные механизмы выбора. Например, нужно сделать выбор между типами T и F согласно условию C: mpl::if_<C, T, F>::type, результатом выражения будет T, если C::value дает true, в противном случае F.
Такой подход можно применть в алгоритме iter_swap используя классы с мнемоническими (более запоминаемыми) именами вместо iter_swap_impl:
Два вида поведения, которые необходимо выбирать в зависимости от условий:
#include <boost/mpl/if.hpp>
struct fast_swap
{
template <class ForwardIterator1, class ForwardIterator2>
static void do_it(ForwardIterator1 i1, ForwardIterator2 i2)
{
std::swap(*i1, *i2);
}
};
struct reliable_swap
{
template <class ForwardIterator1, class ForwardIterator2>
static void do_it(ForwardIterator1 i1, ForwardIterator2 i2)
{
typename
std::iterator_traits<ForwardIterator1>::value_type
tmp = *i1;
*i1 = *i2;
*i2 = tmp;
}
};
В точке «---деспетчеризация поведения---» алгоритма iter_swap теперь можно записать так:
mpl::if_
<
mpl::bool_<use_swap>, // use_swap (1 : 0)
fast_swap,
reliable_swap
>::type::do_it(i1,i2);
Корректировка типа параметров:
Рассмотрим оптимизированный способ заполнения параметров шаблоннов. При передаче аргументов по значению вызывается конструктор копии, который может выполнять нетривиальную работу, потому обобщенная функция содержит ссылочный параметр. Т.о. часто нужно корректировать тип параметра – для этого существует специальный механизм param_type <T>, который возвращает T, когда это - скаляр, и T const& в противном случае (Причина почему скаляр лучше передавать по значению: многие компиляторы оптимизируют передачу скаляров, помещая их в специальные регистры, в то время как, при передаче по ссылке будет использоваться запись стэк).
template <class T>
class holder
{
public:
holder(typename param_type<T>::type x);
//...
private:
T x;
};
При передаче аргумента типа int параметр будет иметь тип int, при передаче аргумента типа vector<int>, параметр будет иметь тип vector<int> const&.
#include <boost/mpl/if.hpp>
#include <boost/type_traits/is_scalar.hpp>
template <class T>
struct param_type
: mpl::if_
<
typename boost::is_scalar<T>::type,
T,
T const&
>
{};
Такое решение имеет недостаток: при передаче аргументу по ссылке образуется тип ссылки на ссылку, что явялется ошибкой. Решение: использование специализаций.
#include <boost/mpl/if.hpp>
#include <boost/type_traits/add_reference.hpp>
template <class T>
struct param_type
: mpl::if_
<
typename boost::is_scalar<T>::type,
T,
typename boost::add_reference<T const>::type // Добавит ссылку если ее еще нет.
>
{};
