- •Вычисления значений
- •Пример:
- •Вычисления типов
- •Преимущества мета подхода:
- •Польза использования mpl:
- •Числовая метафункция
- •Свойства
- •Метаданные
- •Специализация
- •Первичный шаблон:
- •Инстанцирование:
- •Метафункции
- •Полиморфизм
- •Возможности свойств:
- •Организация свойств в Boost:
- •Пример:
- •Типовые ассоциации
- •Альтернатива:
- •Метафункции Продвижение (пересылка) метафункций
- •Класс метафункции
- •Формат:
- •Числовые
- •Пример:
- •Нульарные
- •Метрический анализ (Анализ размерностей)
- •Метрики
- •Величины
- •Сложение и вычитание
- •Умножение
- •Класс метафункции
- •Деление
- •Пример:
- •Метафункции высшего порядка (Каскады вложенных вызовов)
- •Использование apply:
- •Заполнители
- •Безымянный заполнитель:
- •Определение выражений с заполнителями
- •Лямбда (Лямбда метафункции/выражения)
- •Частичное приложение метафункции
- •Лямбда и Шаблоны Неметафункции
- •Обертки
- •Выбор типа
- •Ленивый Выбор Типа
- •Логические Операторы
- •Целочисленные обертки
- •Составные Операторы
- •Операторы с булевым значением:
- •Операторы для сравнения значений:
- •Операторы для интегральных значений:
- •Побитовые операторы:
- •Арифметические операторы:
- •Целочисленная «стенография»
- •Интегральные последовательности
- •Формат:
- •Последовательности
- •Концепции
- •Итераторы
- •Двунаправленные
- •Произвольные
- •Последовательности
- •Двунаправленные
- •Произвольные
- •Расширенные
- •Ассоциативные
- •Требования
- •Расширения
- •Расширенные ассоциативные последовательности
- •Алгоритмы и последовательности
- •Итераторы
- •Равенство
- •Операции Внутренние операции с последовательностей
- •Наследование
- •Создание последовательности
- •Реализация:
- •Создание итератора
- •Преимущества полной специализации перед частичной:
- •Добавление расширения
- •Алгоритмы
- •Абстракция:
- •Stl алгоритмы
- •Детали правильного использования stl:
- •Mpl алгоритмы
- •Различия stl и mpl алгоритмов:
- •Пример:
- •Вставки
- •Пример 1:
- •Пример 2:
- •Пример 3:
- •Фундамент алгоритмов
- •Пример:
- •Запрашиваемые алгоритмы
- •Последовательности (Алгоритмы, создающие последовательности)
- •Синонимы функциональных алгоритмов:
- •Создание алгоритма
- •Итераторы «Просмотр» и итераторы-адаптеры
- •Концепция просмотра
- •Применение просмотра Сравнения значений элементов последовательности:
- •Объединение множественных (мульти-) последовательностей
- •Упрощение 1
- •Упрощение 2 (создание просмотра)
- •Уход от ненужного вычисления
- •Выборочная обработка элемента
- •Итератор-адаптер
- •Создание просмотра
- •Реализация итератора-адаптера для zip_view.
- •Диагностика
- •Отладка ошибок
- •Трассировка инстанцирования
- •Исправленный пример:
- •Форматы сообщений об ошибках
- •Блок «with»
- •Устранение параметров шаблона по умолчанию
- •Глубокий typedef
- •Инструменты
- •Несколько компиляторов
- •(Статические Утверждения)
- •Формат:
- •Формат:
- •Индивидуальные сообщения утверждений
- •Настройка предиката:
- •(Генерирование встроенных сообщений)
- •Формат:
- •Выбор стратегии:
- •Тип печати
- •Кросс этапность компиляции/выполнения
- •Печать типов:
- •Тип посещения:
- •Выбор реализаций
- •Специализация шаблонов классов
- •Тег диспетчеризации
- •Выбор структуры
- •Композиция классов
- •Указатели на функцию
- •Ослабление типизации
- •Пример:
- •Обобщение:
- •Динамический полиморфизм
- •Автоматизация
- •Сохранение интерфейса
- •Рекуррентный шаблон
- •Формат:
- •Генерирование функций
- •Управление разрешением перегрузки
- •Явное управление множеством перегрузки
- •Документация mpl Последовательности
- •Концепции
- •(Прямая последовательность)
- •(Двунаправленная Последовательность)
- •(Последовательность произвольного доступа)
- •(Расширенная последовательность)
- •(Расширенная последовательность начала)
- •(Расширенная последовательность конца)
- •(Ассоциативная последовательность)
- •(Расширенная ассоциативная последовательность)
- •(Обертка интегральной последовательности )
- •(Переменная последовательность)
- •Представления
- •Метафункции (Внутренние)
- •Итераторы
- •Концепции
- •(Прямой итератор)
- •(Двунаправленный итератор)
- •(Итератор произвольного доступа)
- •Метафункции
- •Алгоритмы
- •Концепции
- •(Инсертер: механизм вставок)
- •Инсертеры (инсертер: механизм вставок)
- •Итеративные алгоритмы
- •Запрашиваемые алгоритмы
- •Преобразования
- •Метафункции
- •Концепции Метафункция
- •Метафункциональный класс
- •Лямбда выражения
- •Заполнители
- •Тэг диспетчеризированные метафункции
- •Числовые метафункции
- •Тривиальные метафункции
Класс метафункции
Но это еще не совсем решение. Попытка применить алгоритм transform выполненяя operator* приводит к ошибке компиляции:
#include <boost/mpl/transform.hpp>
template <class T, class D1, class D2>
quantity
<
T,
typename mpl::transform<D1,D2,mpl::plus>::type // нужен полноценный тип, а не имя шаблона
>
operator*(quantity<T, D1> x, quantity<T, D2> y)
{
//...
}
Причина ошибки в том, что протокол говорит, что аргументы метафункции должны быть типами, а plus не тип, а шаблон класса plus<T1, T2>.
Естественный способ ввести полиморфизм между метафункциями и метаданными (создать единообразную форму управления их различными свойствами) - использовать идиому обертки, которая дала нам полиморфизм между типами и целочисленными константами. Вместо вложенной целочисленной константы, мы можем использовать шаблонный класс, вложенный в класс метафункции:
struct plus_f
{
template <class T1, class T2>
struct apply
{
typedef typename mpl::plus<T1,T2>::type type;
};
};
Класс метафункции (метафункциональный класс) - класс с вложенной метафункцией, доступ к которой открыт.
Метафункция - шаблон, а не тип, но класс метафункции, который обертывает такой шаблон в теле обычного нешаблонного класса – является простым типом.
В то время, как метафункции оперируют приемом и возвратом типов, класс метафункции может быть передан в качестве аргумента, или возвращен из другой метафункции.
Теперь BinaryOperation может быть выполнена:
template <class T, class D1, class D2>
quantity
<
T,
typename mpl::transform<D1,D2,plus_f>::type // new dimensions
>
operator*(quantity<T, D1> x, quantity<T, D2> y)
{
typedef typename mpl::transform<D1, D2, plus_f>::type dim;
return quantity<T,dim>( x.value() * y.value() );
}
Теперь, если мы хотим вычислить силу тяжести действующую на пятикилограммовом ноутбуке, это всего лишь ускорение силы тяжести (9.8 m/sec2), вызванной массой ноутбука (умножение):
quantity<float, mass> m(5.0f);
quantity<float, acceleration> a(9.8f);
cout << "force = " << (m * a).value();
Разбор:
typedef mpl::vector_c<int,1,0,0,0,0,0,0> mass;
typedef mpl::vector_c<int,0,1,-2,0,0,0,0> acceleration; // l/(t2)
typedef typename mpl::transform<D1,D2,plus_f>::type dim;
mpl::transform<mass, acceleration, plus_f>::type dim;
1,0, 0,0,0,0,0
0,1,-2,0,0,0,0
+-----------------
1,1,-2,0,0,0,0 // Результирующая последовательность
dim == mpl::vector_c<int,1,1,-2,0,0,0,0>; // Новое размерность: сила тяжести ноутбука в 5 кг
Так, operator* умножает величины во время выполнения (приводящий к 6.0f), и наше кодовое использование метапрограммы преобразовывает метапоследовательности фундаментальных показателей степени так, чтобы тип результата содержал новый список показателей степени:
vector_c<int,1,1,-2,0,0,0,0>;
Но, попытка записать следующее выражение приведет к проблемам:
quantity<float,force> f = m * a;
Хотя результат м * a действительно представляет силу с показателями степени массы, длины, и время как 1, 1, и -2 соответственно, тип, возвращенный преобразованием, не является специализацией vector_c. Вместо этого алгоритм вернет новую последовательность с соответствующими элементами: vector_c <int, 1,1,-2,0,0,0,0>. Дело в том, что quantity<float,force> является другим типом, что и приводит к ошибке.
Решение 1: добавим неявное преобразование результата умножения к типу quantity<float, force> . Так как мы не можем предсказать точные типы размерностей в любом вычислении, то преобразование должно быть шаблонным:
template <class T, class Dimensions>
struct quantity
{
// converting constructor
template <class OtherDimensions>
quantity(quantity<T,OtherDimensions> const& rhs)
: m_value(rhs.value())
{}
//...
}
Но, допустить такие преобразования – это наршуть главную цель строгой статической типизации размерностей. Это позволит записывать заведомо ошибочные выражения:
// Should yield a force, not a mass!
quantity<float, mass> bogus = m * a;
Решение 2: использование дргуого алгоритма MPL – equal, который позволит проверять идентичность элементов двух последовательностей и выполнить преобразование только в случае их равенства:
template <class OtherDimensions>
quantity(quantity<T,OtherDimensions> const& rhs) : m_value(rhs.value())
{
BOOST_STATIC_ASSERT((
mpl::equal<Dimensions,OtherDimensions>::type::value
));
}
