- •Вычисления значений
- •Пример:
- •Вычисления типов
- •Преимущества мета подхода:
- •Польза использования mpl:
- •Числовая метафункция
- •Свойства
- •Метаданные
- •Специализация
- •Первичный шаблон:
- •Инстанцирование:
- •Метафункции
- •Полиморфизм
- •Возможности свойств:
- •Организация свойств в Boost:
- •Пример:
- •Типовые ассоциации
- •Альтернатива:
- •Метафункции Продвижение (пересылка) метафункций
- •Класс метафункции
- •Формат:
- •Числовые
- •Пример:
- •Нульарные
- •Метрический анализ (Анализ размерностей)
- •Метрики
- •Величины
- •Сложение и вычитание
- •Умножение
- •Класс метафункции
- •Деление
- •Пример:
- •Метафункции высшего порядка (Каскады вложенных вызовов)
- •Использование apply:
- •Заполнители
- •Безымянный заполнитель:
- •Определение выражений с заполнителями
- •Лямбда (Лямбда метафункции/выражения)
- •Частичное приложение метафункции
- •Лямбда и Шаблоны Неметафункции
- •Обертки
- •Выбор типа
- •Ленивый Выбор Типа
- •Логические Операторы
- •Целочисленные обертки
- •Составные Операторы
- •Операторы с булевым значением:
- •Операторы для сравнения значений:
- •Операторы для интегральных значений:
- •Побитовые операторы:
- •Арифметические операторы:
- •Целочисленная «стенография»
- •Интегральные последовательности
- •Формат:
- •Последовательности
- •Концепции
- •Итераторы
- •Двунаправленные
- •Произвольные
- •Последовательности
- •Двунаправленные
- •Произвольные
- •Расширенные
- •Ассоциативные
- •Требования
- •Расширения
- •Расширенные ассоциативные последовательности
- •Алгоритмы и последовательности
- •Итераторы
- •Равенство
- •Операции Внутренние операции с последовательностей
- •Наследование
- •Создание последовательности
- •Реализация:
- •Создание итератора
- •Преимущества полной специализации перед частичной:
- •Добавление расширения
- •Алгоритмы
- •Абстракция:
- •Stl алгоритмы
- •Детали правильного использования stl:
- •Mpl алгоритмы
- •Различия stl и mpl алгоритмов:
- •Пример:
- •Вставки
- •Пример 1:
- •Пример 2:
- •Пример 3:
- •Фундамент алгоритмов
- •Пример:
- •Запрашиваемые алгоритмы
- •Последовательности (Алгоритмы, создающие последовательности)
- •Синонимы функциональных алгоритмов:
- •Создание алгоритма
- •Итераторы «Просмотр» и итераторы-адаптеры
- •Концепция просмотра
- •Применение просмотра Сравнения значений элементов последовательности:
- •Объединение множественных (мульти-) последовательностей
- •Упрощение 1
- •Упрощение 2 (создание просмотра)
- •Уход от ненужного вычисления
- •Выборочная обработка элемента
- •Итератор-адаптер
- •Создание просмотра
- •Реализация итератора-адаптера для zip_view.
- •Диагностика
- •Отладка ошибок
- •Трассировка инстанцирования
- •Исправленный пример:
- •Форматы сообщений об ошибках
- •Блок «with»
- •Устранение параметров шаблона по умолчанию
- •Глубокий typedef
- •Инструменты
- •Несколько компиляторов
- •(Статические Утверждения)
- •Формат:
- •Формат:
- •Индивидуальные сообщения утверждений
- •Настройка предиката:
- •(Генерирование встроенных сообщений)
- •Формат:
- •Выбор стратегии:
- •Тип печати
- •Кросс этапность компиляции/выполнения
- •Печать типов:
- •Тип посещения:
- •Выбор реализаций
- •Специализация шаблонов классов
- •Тег диспетчеризации
- •Выбор структуры
- •Композиция классов
- •Указатели на функцию
- •Ослабление типизации
- •Пример:
- •Обобщение:
- •Динамический полиморфизм
- •Автоматизация
- •Сохранение интерфейса
- •Рекуррентный шаблон
- •Формат:
- •Генерирование функций
- •Управление разрешением перегрузки
- •Явное управление множеством перегрузки
- •Документация mpl Последовательности
- •Концепции
- •(Прямая последовательность)
- •(Двунаправленная Последовательность)
- •(Последовательность произвольного доступа)
- •(Расширенная последовательность)
- •(Расширенная последовательность начала)
- •(Расширенная последовательность конца)
- •(Ассоциативная последовательность)
- •(Расширенная ассоциативная последовательность)
- •(Обертка интегральной последовательности )
- •(Переменная последовательность)
- •Представления
- •Метафункции (Внутренние)
- •Итераторы
- •Концепции
- •(Прямой итератор)
- •(Двунаправленный итератор)
- •(Итератор произвольного доступа)
- •Метафункции
- •Алгоритмы
- •Концепции
- •(Инсертер: механизм вставок)
- •Инсертеры (инсертер: механизм вставок)
- •Итеративные алгоритмы
- •Запрашиваемые алгоритмы
- •Преобразования
- •Метафункции
- •Концепции Метафункция
- •Метафункциональный класс
- •Лямбда выражения
- •Заполнители
- •Тэг диспетчеризированные метафункции
- •Числовые метафункции
- •Тривиальные метафункции
Ленивый Выбор Типа
Подход с инстанцированием add_reference <T const> явялется неэффективным, т.к. будет всегда вызываться даже если аргумент имеет тип скаляра. Есть способ отложить инстанцирование add_reference до реальной необходимости – это позволить mpl::if_ делать выбор из двух нульарных метафункций, в результате чего инстанцироваться будет только выбранная:
#include <boost/mpl/if.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/type_traits/add_reference.hpp>
template <class T>
struct param_type
: mpl::if_ // forwarding to selected transformation
<
typename boost::is_scalar<T>::type,
mpl::identity<T>,
boost::add_reference<T const>
>::type
{};
mpl::identity - метафункция, которая возвращает свой аргумент. Теперь param_type<T> возвращает результат вызова любого mpl::identity <T> или add_reference <T const>, в зависимости от того, является ли T скаляром. Эта идиома настолько распространена в метапрограммах, что MPL создает для нее отдельную метафункцию, названную eval_if:
template <class C, class TrueMetafunc, class FalseMetafunc>
struct eval_if
: mpl::if_<C,TrueMetafunc,FalseMetafunc>::type
{};
Принимая во внимание, что if_ возвращает один из двух аргументов, основанных на условии, eval_if вызывает один из двух аргументов нульарной метафункции, согласно условию и возвращает результат.
Теперь можно немного упростить определение param_type, с помощью eval_if:
#include <boost/mpl/eval_if.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/type_traits/add_reference.hpp>
template <class T>
struct param_type
: mpl::eval_if
<
typename boost::is_scalar<T>::type,
mpl::identity<T>,
boost::add_reference<T const>
> // no ::type here
{};
Используя тот факт, что все целочисленные метацфункции содержат элемент «::value», может написать следующее:
template <class T>
struct param_type
: mpl::eval_if
<
boost::is_scalar<T>, //! Неявное преобразование к вложенному типу
mpl::identity<T>,
boost::add_reference<T const>
>
{};
Специализации метафункций таких как is_scalar, возвращают константные целочисленные обертки публично полученные от внешней обертки, а также элементы наследуемого базового класса, например: bool_:
if(boost::is_scalar<X>()) // invokes inherited operator bool()
{
// code here runs iff X is a scalar type
}
Логические Операторы
Если бы не было механизма наподобии add_reference или он был бы определен как показано ниже, то мы не могли бы избежать возможного возникновения ссылки на ссылку:
template <class T>
struct add_reference { typedef T& type; };
В этом случае пришлось бы переделывать param_type подобно следующей конструкции:
template <class T>
struct param_type
: mpl::eval_if
<
mpl::bool_
<
boost::is_scalar<T>::value ||
boost::is_reference<T>::value
>,
mpl::identity<T>,
add_reference<T const>
>
{};
Большая часть синтаксической чистоты нашей предыдущей версии была потеряна. Если бы мы хотели построить лямбда выражение для этой версии param_type, то возникли бы еще более серьезные проблемы:
typedef mpl::vector<int, long, std::string> argument_types;
// build a list of parameter types for the argument types
typedef mpl::transform
<
argument_types,
mpl::if_
<
mpl::bool_
<
boost::is_scalar<_1>::value ||
boost::is_reference<_1>::value
>,
mpl::identity<_1>,
add_reference<boost::add_const<_1>
>
>::type param_types;
Это уже фактически не в состоянии работать должным образом: логическое выражения:: is_scalar <_1>::value || is_reference <_1>::value будут вычисляться даже если «_1» не является скаляром и ссылкой. Можно решить обе эти проблемы, используя логические метафункции MPL. Решение: добавление и в этот процесс дополнительного уровня абстракции в виде метафункции mpl::or_, что позволит вернуть синтаксическую чистоту оригинального param_type:
#include <boost/mpl/or.hpp>
template <class T>
struct param_type
: mpl::eval_if
<
mpl::or_ // будет инстанцирована
<
boost::is_scalar<T>,
boost::is_reference<T>
>,
mpl::identity<T>,
add_reference<T const>
>
{};
Поскольку mpl::or_ <x, y> выводит тип «::type»(специализация bool _<n>), что явялется допустимой булевой константой оберткой в MPL, мы в состоянии полностью устранить явное использование bool_ и доступа к вложенному «::type».
Несмотря на то, что логическая метафункция не совсем используется по назначению, но в результате мы имеем более удобочитаемый код.
Эта выгода усиливается при использовании такого подхода в лямбда выражениях:
typedef mpl::transform
<
argument_types,
mpl::if_
<
mpl::or_
<
boost::is_scalar<_1>,
boost::is_reference<_1>
>,
mpl::identity<_1>,
add_reference<boost::add_const<_1>
>
>::type param_types;
Если необходимо изменить param_type так, чтобы указать другие недопустимые типы для параметров класса, в дополнение к скалярам и передачи по значению, можно использовать вложенные вызовы or_:
#include <boost/type_traits/is_stateless.hpp>
template <class T>
struct param_type
: mpl::eval_if
<
mpl::or_
<
boost::is_stateless<T>,
mpl::or_
<
boost::is_scalar<T>,
boost::is_reference<T>
>
>,
mpl::identity<T>,
add_reference<T const>
>
{};
Это работает, но можно сделать этот код более читабельным, т.к. mpl::or_ способен принимать от двух до пяти аргументов:
#include <boost/type_traits/is_stateless.hpp>
template <class T>
struct param_type
: mpl::eval_if
<
mpl::or_
<
boost::is_scalar<T>,
boost::is_stateless<T>,
boost::is_reference<T>
>,
mpl::identity<T>,
add_reference<T const>
>
{};
Фактически, большинство метафункций MPL, которые опрерируют целочисленными константными аргументами (например, mpl::plus<...>), имеют то же самое свойство.
Библиотека содержит подобную логическую метафункцию and_, и унарную метафункцию not_ для того, чтобы инвертировать булевые условия. Это работает так же как встроенные операторы «&&» и «||», mpl::and_ и mpl::or_ - это прямая деонстрация поведения «короткого замыкания».
Например, в примере выше, если T - скаляр, is_stateless <T> и is_reference <T> не будут инстанцироваться.
