- •Вычисления значений
- •Пример:
- •Вычисления типов
- •Преимущества мета подхода:
- •Польза использования mpl:
- •Числовая метафункция
- •Свойства
- •Метаданные
- •Специализация
- •Первичный шаблон:
- •Инстанцирование:
- •Метафункции
- •Полиморфизм
- •Возможности свойств:
- •Организация свойств в Boost:
- •Пример:
- •Типовые ассоциации
- •Альтернатива:
- •Метафункции Продвижение (пересылка) метафункций
- •Класс метафункции
- •Формат:
- •Числовые
- •Пример:
- •Нульарные
- •Метрический анализ (Анализ размерностей)
- •Метрики
- •Величины
- •Сложение и вычитание
- •Умножение
- •Класс метафункции
- •Деление
- •Пример:
- •Метафункции высшего порядка (Каскады вложенных вызовов)
- •Использование apply:
- •Заполнители
- •Безымянный заполнитель:
- •Определение выражений с заполнителями
- •Лямбда (Лямбда метафункции/выражения)
- •Частичное приложение метафункции
- •Лямбда и Шаблоны Неметафункции
- •Обертки
- •Выбор типа
- •Ленивый Выбор Типа
- •Логические Операторы
- •Целочисленные обертки
- •Составные Операторы
- •Операторы с булевым значением:
- •Операторы для сравнения значений:
- •Операторы для интегральных значений:
- •Побитовые операторы:
- •Арифметические операторы:
- •Целочисленная «стенография»
- •Интегральные последовательности
- •Формат:
- •Последовательности
- •Концепции
- •Итераторы
- •Двунаправленные
- •Произвольные
- •Последовательности
- •Двунаправленные
- •Произвольные
- •Расширенные
- •Ассоциативные
- •Требования
- •Расширения
- •Расширенные ассоциативные последовательности
- •Алгоритмы и последовательности
- •Итераторы
- •Равенство
- •Операции Внутренние операции с последовательностей
- •Наследование
- •Создание последовательности
- •Реализация:
- •Создание итератора
- •Преимущества полной специализации перед частичной:
- •Добавление расширения
- •Алгоритмы
- •Абстракция:
- •Stl алгоритмы
- •Детали правильного использования stl:
- •Mpl алгоритмы
- •Различия stl и mpl алгоритмов:
- •Пример:
- •Вставки
- •Пример 1:
- •Пример 2:
- •Пример 3:
- •Фундамент алгоритмов
- •Пример:
- •Запрашиваемые алгоритмы
- •Последовательности (Алгоритмы, создающие последовательности)
- •Синонимы функциональных алгоритмов:
- •Создание алгоритма
- •Итераторы «Просмотр» и итераторы-адаптеры
- •Концепция просмотра
- •Применение просмотра Сравнения значений элементов последовательности:
- •Объединение множественных (мульти-) последовательностей
- •Упрощение 1
- •Упрощение 2 (создание просмотра)
- •Уход от ненужного вычисления
- •Выборочная обработка элемента
- •Итератор-адаптер
- •Создание просмотра
- •Реализация итератора-адаптера для zip_view.
- •Диагностика
- •Отладка ошибок
- •Трассировка инстанцирования
- •Исправленный пример:
- •Форматы сообщений об ошибках
- •Блок «with»
- •Устранение параметров шаблона по умолчанию
- •Глубокий typedef
- •Инструменты
- •Несколько компиляторов
- •(Статические Утверждения)
- •Формат:
- •Формат:
- •Индивидуальные сообщения утверждений
- •Настройка предиката:
- •(Генерирование встроенных сообщений)
- •Формат:
- •Выбор стратегии:
- •Тип печати
- •Кросс этапность компиляции/выполнения
- •Печать типов:
- •Тип посещения:
- •Выбор реализаций
- •Специализация шаблонов классов
- •Тег диспетчеризации
- •Выбор структуры
- •Композиция классов
- •Указатели на функцию
- •Ослабление типизации
- •Пример:
- •Обобщение:
- •Динамический полиморфизм
- •Автоматизация
- •Сохранение интерфейса
- •Рекуррентный шаблон
- •Формат:
- •Генерирование функций
- •Управление разрешением перегрузки
- •Явное управление множеством перегрузки
- •Документация mpl Последовательности
- •Концепции
- •(Прямая последовательность)
- •(Двунаправленная Последовательность)
- •(Последовательность произвольного доступа)
- •(Расширенная последовательность)
- •(Расширенная последовательность начала)
- •(Расширенная последовательность конца)
- •(Ассоциативная последовательность)
- •(Расширенная ассоциативная последовательность)
- •(Обертка интегральной последовательности )
- •(Переменная последовательность)
- •Представления
- •Метафункции (Внутренние)
- •Итераторы
- •Концепции
- •(Прямой итератор)
- •(Двунаправленный итератор)
- •(Итератор произвольного доступа)
- •Метафункции
- •Алгоритмы
- •Концепции
- •(Инсертер: механизм вставок)
- •Инсертеры (инсертер: механизм вставок)
- •Итеративные алгоритмы
- •Запрашиваемые алгоритмы
- •Преобразования
- •Метафункции
- •Концепции Метафункция
- •Метафункциональный класс
- •Лямбда выражения
- •Заполнители
- •Тэг диспетчеризированные метафункции
- •Числовые метафункции
- •Тривиальные метафункции
Блок «with»
В дампе VC ++ 6 виден вызов std::copy. Чтобы сделать тот факт более очевидным, мноие компиляторы отделяют фактические аргументы шаблона от имен шаблонных специализаций.
Например, заключительная строка дампа в GCC:
/usr/include/c++/3.2/bits/stl_algobase.h:349: instantiated from
'_OutputIter std::copy(_InputIter, _InputIter, _OutputIter)
[with _InputIter = std::_List_iterator<std::string, std::string&,
std::string*>, _OutputIter = std::back_insert_iterator<std::map<
std::string, std::string, std::less<std::string>, std::allocator<
std::pair<const std::string, std::string> > > >]'
messages continue...
Зарезервированные идентификаторы:
Стандарт C++ резервирует идентификаторы, которые начинаются с подчеркивания и прописной буквы (как _InputIter) и идентификаторы, содержащие двойные подчеркивания (__FUNCTION__) для использования реализацией языка, стандартная библиотека использует эти имена для внутренних реализаций, их явное использование в пользовательном коде может привести к неопределенности.
Так, видно что к сигнатуре std::copy применяется данный подход, что дает информацию о требованиях концепции для передачи аргументов параметрам.
В MCVC 7 был также применен данных подход и введены полезные разрывы строк:
foo.cpp(10) : see reference to function template instantiation
'_OutIt std::copy(_InIt,std::list<_Ty,_Ax>::iterator,
std::back_insert_iterator<_Container>)' being compiled
with
[
_OutIt=std::back_insert_iterator<std::map<std::string,std
::string,std::less<std::string>,std::allocator<std::pair<
const std::string,std::string>>>>,
_InIt=std::list<std::string,std::allocator<std::string>>::iterator,
_Ty=std::string,
_Ax=std::allocator<std::string>,
_Container=std::map<std::string,std::string,std::less<std
::string>,std::allocator<std::pair<const std::string,std::
string>>>
]
К сожалению, при этом, выводится также информация, которая не требуется. Вместо того, чтобы повторить дважды _InIt и _OutIt в сигнатуре функции, второй и третий типы параметров записываются в полном объеме и повторяется в блоке «with».
Устранение параметров шаблона по умолчанию
В версии 7.1 Microsoft исправили это, позволяя видеть, что первые два параметра в std::copy имеют одинаковый тип.
foo.cpp(10) : see reference to function template instantiation '
_OutIt std::copy<std::list<_Ty>::iterator,std::
back_insert_iterator<_Container> >(_InIt,_InIt,_OutIt)' being
compiled
with
[
_OutIt=std::back_insert_iterator<std::map<std::string,std::
string>>,
_Ty=std::string,
_Container=std::map<std::string,std::string>,
_InIt=std::list<std::string>::iterator
]
messages continue...
Если бы выделенный участок выше, заменить на std::copy<_InIt, _OutIt>, то элемент _Ty, можно было бы вынести из блока «with».
Тот факт, что параметр по умолчанию был проигнорирован в дампе – упрощает сообщение.
Глубокий typedef
Много современные компиляторы пытаются помнить, был ли и если да, то как переопределен каждый тип (не только в контексте одного пространства имен), поэтому тип может быть отобажен в дампе в удобной форме - стратегия глубоких переопределений посредством typedef.
Например:
#include <map>
#include <vector>
#include <algorithm>
int main()
{
std::map<int,int> a;
std::vector<int> v(20);
std::copy(a.begin(), a.end(), v.begin());
return 0;
}
Приводит к следующему дампу в Intel C++ 8.0:
C:\Program Files\Microsoft Visual Studio .NET 2003\VC7\INCLUDE\
xutility(1022): error: no suitable conversion function from "std::
allocator<std::pair<const int, int>>::value_type" to "std::
allocator <std::_Tree<std::_Tmap_traits<int, int, std::less<int>,
std::allocator<std::pair<const int, int>>, false>>::key_type=
{std::_Tmap_traits<int, int, std::less<int>, std::allocator<std::
pair<const int, int>>, false>::key_type={int}}>::value_type=
{std::_Allocator_base<std::_Tree<std::_Tmap_traits<int, int,
std::less<int>, std::allocator<std::pair<const int, int>>,
false>>::key_type={std::_Tmap_traits<int, int, std::less<
int>, std::allocator<std::pair<const int, int>>, false>::
key_type={int}}>::value_type={std::_Tree<std::_Tmap_traits
<int, int, std::less<int>, std::allocator<std::pair<const
int, int>>, false>>::key_type={std::_Tmap_traits<int, int,
std::less<int>, std::allocator<std::pair<const int, int>>,
false>::key_type={int}}}}" exists
*_Dest = *_First;
^
...
Проблема состоит в том, что нельзя выполнить присвоение pair <int, int> (map элемент) в int (элемент vector). В сообщении, этот факт, очень сложно обнаружить. В идеальном случае, сообщение должно было быть таким:
Нельзя преобразовать вложенный элемент value_type из:
allocator<pair<int,int>>
во вложенный элемент value_type из:
_allocator<
_Tree<...>::key_type... (which is some
_Tmap_traits<...>::key_type, which is int)
>
Т.к. второй value_type из
_Allocator_base<
_Tree<...>::key_type... (which is some
_Tmap_traits<...>::key_type, which is int)
>
имеет тип key_type в _Tree <...>, с аргументом типа int.
В результате, вместо того, чтобы просто указать для каких элементов нельзя выполнить преобразование, была выведена информация о том, как эти элементы были получены в реализации стандартной библиотеки.
Вот как выглядит сообщение о той же ошибке в MSVC 7.1:
C:\Program Files \Microsoft Visual Studio .NET 2003\Vc7 \include\
xutility(1022) : error C2440: '=' : cannot convert from 'std::
allocator<_Ty>::value_type' to 'std::allocator<_Ty>::value_type'
with
[
_Ty=std::pair<const int,int>
]
and
[
_Ty=std::_Tree<std::_Tmap_traits<int,int,std::less<
int>,std::allocator<std::pair<const int,int>>,
false>>::key_type
]
...
Это сообщение намного короче, но это не обязательно хорошо: дамп сообщает, что std::allocator<_Ty>::value_type не может быть преобразован к своему собственному типу, а насамом деле имеется в виду разнве типы _Ty в блоках «with» и «and».
Хорошо знать, что известно, что «::value_type» является вложенным элементом в std::allocator и явялется типом переданного аргумента, если бы не этот однообразный подход, по имени value_type нельзя было бы сказать ничего конкретного.
Так как std::allocator<_Ty>::value_type является по существу метафункциональным вызовов, этот вид глубокого перелпределения посредством typedef является важным фактором для отладки метапрограммы.
Пример:
#include <boost/mpl/transform.hpp>
#include <boost/mpl/vector/vector10.hpp>
namespace mpl = boost::mpl;
using namespace mpl::placeholders;
template <class T>
struct returning_ptr
{
typedef T* type();
};
typedef mpl::transform<
mpl::vector5<int&,char,long[5],bool,double>,
returning_ptr<_1>
>::type functions;
Задача заключалась в том, чтобы создать последовательность типов функций, возвращающих указатели на типы во входной последовательности, но автор забыл учесть тот факт, что формирование указателя на ссылочный тип (int&) недопустимо в C++.
C++ Intel 7.1 выдает такой отчет:
foo.cpp(19): error: pointer to reference is not allowed
typedef T* type();
^
detected during:
instantiation of class "returning_ptr<T> [with T=boost::
mpl::bind1<boost::mpl::quote1<returning_ptr>, boost::mpl
::lambda_impl<boost::mpl::_1, boost::mpl::false_>::type>
::apply<boost::mpl::vector_iterator<boost::mpl::vector5<
int &, char, long [5], bool={bool}, double>::type, boost
::mpl::integral_c<long, 0L>>::type, boost::mpl::void_,
boost::mpl::void_, boost::mpl::void_, boost::mpl::void_>
::t1]" at line 23 of "c:/boost/boost/mpl/aux_/has_type.
hpp"
Вцелом сообщение верное, но проблема совершенно в ином. Мы действительно хотели бы знать, какия является тип T в момент ошибки, но он выражается с точки зрения вложенного переопределения типа: mpl::bind1 <...>::t1.
В MSVC 10:
см. ссылку на создание экземпляров класса шаблон при компиляции "returning_ptr<T>"
with
[
T=int &
]
