Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
template_metaprogramming_ru.docx
Скачиваний:
12
Добавлен:
01.07.2025
Размер:
774 Кб
Скачать
☆

Кросс этапность компиляции/выполнения

for_each

Алгоритм std::for_each имеет своего аналога в MPL, который работает подобным образом. Так, std:: for_each делает обход (во время выполнения) всех элементов последовательности, вызывает некоторые функторы (времени выполнения) для каждого элемента. Алгоритм mpl::for_each делает обход (во время компиляции) всех элементов последовательности, вызывает некоторые функторы (времени выполнения)для каждого элемента. Хотя std::for_each работает только во время выполнения, mpl:: for_each представляет собой гибрид, поддерживающий кросс-этапность своего выполнения.

Причина, по которой mpl:: for_each использует функторы времени выполнения, вместо метафункций: как правило, функторы, использующиеся в std:: for_each имеют тип возвращаемого значения void, но даже, если возвращаемое значение есть, то оно не учитывается. Т.о. цель функтора в алгоритме for_each –приводить к изменению состояний. Поскольку функциональное программирование по своей сути не имеет состояний, а шаблонные метапрограммы являются функциональными, то нет особого смысла в вызове метафункций, для каждого элемента последовательности, если с этими результатами ничего нельзя сделать.

Печать типов:

При использовании механизмов type_info можно распечатать каждый элемент последовательности типов следующим образом:

struct print_type

{

template <class T>

void operator()(T) const

{

std::cout << typeid(T).name() << std::endl;

}

};

typedef mpl::vector<int, long, char*> s;

int main()

{

mpl::for_each<s>(print_type());

return 0;

}

Оператор вызова функций в теле print_type является шаблонным, потому что он должен обрабатывать любой тип, который находится в последовательности. Если в последовательности представлены типы, которые могут быть преобразованы к одному типу или, если, для каждого типа в списке есть перегруженная функция, то оператор вызова не обязан быть шаблонным для использования mpl::for_each.

Алгоритм for_each передает каждый элемент последовательности как значение для инициализации объекта соответствующего типа элемента. Эта форма особенно удобна для осуществления итераций по последовательности интегральных константных оберток, которые неявно преобразовываются в соответствующие константы времени выполнения. При работе с обычной последовательностью типов требуется некоторая осторожность: если элемент оказывается ссылочным типом, классом без конструктора по умолчанию, или просто типом void, то для этих типов алгоритм не сможет выполнить инициализацию объекта значением, что приведет к сбою.

Инициализация объекта значением – сопоставление шаблонного типа Т с переданным типом из списка. Для инициализации значением типа Т, необходимо выполнение следующих требований:

  • Если T является типом класса, который содержить хотя бы 1 конструктор (не по умолчанию), то обязательно, в теле класса, должен быть явно объявлен конструктор по умолчанию.

  • Если Т не является объединением и не содержит объявленных пользователем конструкторов, то каждый нестатический элемент данных и элементы его базового класса типа Т могут быть инициализированы значением.

  • Если T является типом массива, то для каждого элемента выполняется инициализация значением.

В противном случае, объект не будет инициализирован.

Можно избежать некоторые проблемные места, прмиеняя специальные шаблонные обертки:

template <class T>

struct wrap{};

// contains references

typedef mpl::vector<int&, long&, char*&> s; // !"*&"

mpl::for_each<

mpl::transform<s, wrap<_1> // поместит все типы в обертки.

>::type>(print_type());

Нюанс: ссылка на указатель «*&» допускается, что приведет к ведению работы с оригиналом указателя, но указатель на ссылку «&*» недопустим. Предотвратить возможное появление указателя на ссылку можно использованием свойств.

Необходимо изменить также сигнатуру функтора , от которой зависит вывод типов передаваемых аргументов:

struct print_type

{

template <class T>

void operator()(wrap<T>) const // deduce T

{

std::cout << typeid(T).name() << std::endl;

}

};

Для поддержки этой идиомы, MPL предоставляет вторую форму алгоритма mpl::far_each, который принимает метафункции преобразования в качестве дополнительного аргумента шаблона, что позвоялет избежать явного создания новой последовательности:

mpl::for_each<s, wrap<_1>>(print_type());

Каждый элемент Т последовательности s , будет передан функтору print_type в качестве аргумента типа warp<T>.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]