- •Вычисления значений
- •Пример:
- •Вычисления типов
- •Преимущества мета подхода:
- •Польза использования mpl:
- •Специализация
- •Первичный шаблон:
- •Инстанцирование:
- •Метафункции
- •Числовая метафункция
- •Свойства
- •Метаданные
- •Полиморфизм
- •Возможности свойств:
- •Организация свойств в Boost:
- •Пример:
- •Типовые ассоциации
- •Альтернатива:
- •Метафункции Продвижение (пересылка) метафункций
- •Класс метафункции
- •Формат:
- •Числовые
- •Пример:
- •Нульарные
- •Метрический анализ (Анализ размерностей)
- •Метрики
- •Величины
- •Сложение и вычитание
- •Умножение
- •Класс метафункции
- •Деление
- •Пример:
- •Метафункции высшего порядка (Каскады вложенных вызовов)
- •Использование apply:
- •Заполнители
- •Безымянный заполнитель:
- •Определение выражений с заполнителями
- •Лямбда (Лямбда метафункции/выражения)
- •Частичное приложение метафункции
- •Лямбда и Шаблоны Неметафункции
- •Обертки
- •Выбор типа
- •Ленивый Выбор Типа
- •Логические Операторы
- •Целочисленные обертки
- •Составные Операторы
- •Операторы с булевым значением:
- •Операторы для сравнения значений:
- •Операторы для интегральных значений:
- •Побитовые операторы:
- •Арифметические операторы:
- •Целочисленная «стенография»
- •Интегральные последовательности
- •Формат:
- •Последовательности
- •Концепции
- •Итераторы
- •Двунаправленные
- •Произвольные
- •Последовательности
- •Двунаправленные
- •Произвольные
- •Расширенные
- •Ассоциативные
- •Требования
- •Расширения
- •Расширенные ассоциативные последовательности
- •Алгоритмы и последовательности
- •Итераторы
- •Равенство
- •Операции Внутренние операции с последовательностей
- •Наследование
- •Создание последовательности
- •Реализация:
- •Создание итератора
- •Преимущества полной специализации перед частичной:
- •Добавление расширения
- •Алгоритмы
- •Абстракция:
- •Stl алгоритмы
- •Детали правильного использования stl:
- •Mpl алгоритмы
- •Различия stl и mpl алгоритмов:
- •Пример:
- •Вставки
- •Пример 1:
- •Пример 2:
- •Пример 3:
- •Фундамент алгоритмов
- •Пример:
- •Запрашиваемые алгоритмы
- •Последовательности (Алгоритмы, создающие последовательности)
- •Синонимы функциональных алгоритмов:
- •Создание алгоритма
- •Итераторы «Просмотр» и итераторы-адаптеры
- •Концепция просмотра
- •Применение просмотра Сравнения значений элементов последовательности:
- •Упрощение 1
- •Упрощение 2 (создание просмотра)
- •Объединение множественных (мульти-) последовательностей
- •Уход от ненужного вычисления
- •Выборочная обработка элемента
- •Итератор-адаптер
- •Создание просмотра
- •Реализация итератора-адаптера для zip_view.
- •Диагностика
- •Отладка ошибок
- •Трассировка инстанцирования
- •Исправленный пример:
- •Форматы сообщений об ошибках
- •Блок «with»
- •Устранение параметров шаблона по умолчанию
- •Глубокий typedef
- •Инструменты
- •Несколько компиляторов
- •(Статические Утверждения)
- •Формат:
- •Формат:
- •Индивидуальные сообщения утверждений
- •Настройка предиката:
- •(Генерирование встроенных сообщений)
- •Формат:
- •Выбор стратегии:
- •Тип печати
- •Кросс этапность компиляции/выполнения
- •Печать типов:
- •Тип посещения:
- •Выбор реализаций
- •Специализация шаблонов классов
- •Тег диспетчеризации
- •Выбор структуры
- •Композиция классов
- •Указатели на функцию
- •Ослабление типизации
- •Пример:
- •Обобщение:
- •Динамический полиморфизм
- •Автоматизация
- •Сохранение интерфейса
- •Рекуррентный шаблон
- •Формат:
- •Генерирование функций
- •Управление разрешением перегрузки
- •Явное управление множеством перегрузки
- •Документация mpl Последовательности
- •Концепции
- •(Прямая последовательность)
- •(Двунаправленная Последовательность)
- •(Последовательность произвольного доступа)
- •(Расширенная последовательность)
- •(Расширенная последовательность начала)
- •(Расширенная последовательность конца)
- •(Ассоциативная последовательность)
- •(Расширенная ассоциативная последовательность)
- •(Обертка интегральной последовательности )
- •(Переменная последовательность)
- •Представления
- •Метафункции (Внутренние)
- •Итераторы
- •Концепции
- •(Прямой итератор)
- •(Двунаправленный итератор)
- •(Итератор произвольного доступа)
- •Метафункции
- •Алгоритмы
- •Концепции
- •(Инсертер: механизм вставок)
- •Инсертеры (инсертер: механизм вставок)
- •Итеративные алгоритмы
- •Запрашиваемые алгоритмы
- •Преобразования
- •Метафункции
- •Концепции Метафункция
- •Метафункциональный класс
- •Лямбда выражения
- •Заполнители
- •Тэг диспетчеризированные метафункции
- •Числовые метафункции
- •Тривиальные метафункции
C++шаблонное метапрограммирование.
Соглашения именований:
Когда метафункции есть соответствующий встроенный C ++ оператор, то ее имя сопровождается подчеркиванием, например: mpl::and_. Для каждого имени, заканчивающегося подчеркиванием «ХХХ_» существет отдельный «*.hpp» файл.
Иначе, метафункция MPL берет свое имя от соответствующего объекта функции STL, напимер: mpl::equal_to.
Использование «_c»: применяется к именам, если шаблоны принимают «голые» целочисленные константы, вместо оберток, как параметры. Суффикс «_c» может считаться сокращением от «const».
Основы
Шаблонные программы полностью совместимы со старым кодом С++, дополняют и и расширяют существующие языковые идиомы.
Пример простой метапрограммы:
#include "libs/mpl/book/chapter1/binary.hpp"
#include <iostream>
int main()
{
std::cout << binary<101010>::value << std::endl;
return 0;
}
Данный код посчитает битовый набор как число 42 даже без запуска.
Метапрограмма – программа порождающая программы.
Префикс «мета» переводится с греческого как «над» состояние, переход к чему-л. другому, перемена состояния.
Примеры метапрограмм:
Компилятор: на основе кода С++ генерирует код ассемблера и машинный код.
Генераторы синтаксического анализатора, такие как YACC - высокоуровневое описание синтаксического анализатора, записанное с точки зрения правил грамматики и присоединенных включенных в фигурную скобку действий.
Например, чтобы проанализировать и оценить арифметические выражения с обычными правилами приоритетов, мы могли бы подать YACC следующее описание грамматики:
expression : term
| expression '+' term { $$ = $1 + $3; }
| expression '-' term { $$ = $1 - $3; }
;
term : factor
| term '*' factor { $$ = $1 * $3; }
| term '/' factor { $$ = $1 / $3; }
;
factor : INTEGER
| group
;
group : '(' expression ')'
;
В ответе YACC генерировал бы исходный файл C/C++, содержащий функцию yyparse, которую мы можем вызвать, чтобы проанализировать текст:
int main()
{
extern int yyparse();
return yyparse();
}
Доменный язык синтаксического анализатора будет сконвертирован в стандартный язык С, который будет скопилирован и сосединен с другим кодом.
Вывод: метапрогрммирование лежит в основах самого языка.
Вычисления значений
Самые ранние метапрограммы C++ выполняли целочисленные вычисления во время компиляции. Одну из самых первых метапрограмм показал на заседании комитета C++ Эрвин Анрух; это был фактически недопустимый и ошибочный фрагмент кода, сообщения об ошибках которого содержали последовательность вычисленных простых чисел!
На основе таких команд было рождено новое направление программирования и недопустимое стало не только допустимым, но и крайне эффективным.
Пример:
template <unsigned long N>
struct binary
{
static unsigned const value =
binary<N/10>::value << 1 | N%10; // prepend higher bits to lowest bit
};
template <> // specialization terminates recursion
struct binary<0>
{
static unsigned const value = 0;
};
unsigned const one = binary<1>::value;
unsigned const three = binary<11>::value;
unsigned const five = binary<101>::value;
unsigned const seven = binary<111>::value;
unsigned const nine = binary<1000011001>::value;
// ======================================
// Разбор:
// binary<1>
// N = 1 (0000 0001)
// binary<1/10>::value = 0 (0000 0000)
// Приоритеты: "%" "<<" "|":
// 1%10 == 1 (0000 0001);
// 0000 0000 << 1 == 0000 0001;
// 0000 0001 | 0000 0001 == 0000 0001 (1);
// ======================================
unsigned const three = binary<11>::value;
// ======================================
// Разбор:
// binary<11>
// N = 11 (0000 1011)
// binary<11/10>::value = 1 (0000 0001)
// binary<1/10>::value = 0 (0000 0000)
// Приоритеты: "%" "<<" "|":
// 1%10 == 1 (0000 0001);
// 0000 0000 << 1 == 0000 0001;
// 0000 0001 | 0000 0001 == 0000 0001 (1);
// Приоритеты: "%" "<<" "|":
// 11%10 == 1 (0000 0001)
// 0000 0001 << 1 == 0000 0010 (2)
// 0000 0001 | 0000 0010 == 0000 0011 == 3
// ======================================
Требование: стоит передвать только набор из единиц и нулей, иначе результат будет ошибочен, хотя и посчитан.
Так происходит рекурсивное инстацнирование шаблона для аргумента N/10 пока не будет достигунт 0 – признак завершения рекурсии, после чего на этапе «сворачивания» рекурсии будет осуществлен расчет.
Аналогичный алгоритм времени выполнения:
unsigned Binary(unsigned long N)
{
return N == 0 ? 0 : N%10 + 2 * Binary(N/10);
}
Основные отличия:
Способ, которым обработаны условия завершения рекурсии; матаалгоритм использует шаблонную специализацию, чтобы описать то, что происходит, когда N - нуль. Завершающиеся специализации - общая характеристика почти всех метапрограмм C++, хотя в некоторых случаях они будут скрыты позади интерфейса библиотеки метапрограммирования.
Версия этапа выполнения также делает проверку на равенство нулю, другая версия делает то же самое, но итеративно в цикле:
unsigned Binary(unsigned long N)
{
unsigned result = 0;
for(unsigned bit = 0x1; N; N /= 10, bit <<= 1)
{
if(N%10) result += bit;
}
return result;
}
Итеративная версия более читабильная и быстрая.
Рекурсия – двигатель метапрограмм, т.к. на этеп компиляций не существует изменчивых значений, по изменению которых можно было бы судить завершать работу «цикла» или нет, поэтому возможны только бесконечные (пределы определены компилятором) специализации шаблона с разными аргументами посредством рекурсии.
