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

Деление

Деление подобно умножению, но вместо того, чтобы добавлять показатели степеней, мы должны их вычетать. Реализуем для этого minus_f:

struct minus_f

{

template <class T1, class T2>

struct apply : mpl::minus<T1,T2> {}; // Наследование позволяет использовать minus

};

Здесь к minus_f:: применяется наследование, что автоматически использует вложенный тип базового класса, mpl::minus, таким образом, мы не обязаны писать:

typedef typename ...::type type

он будет подхвачен из базового класса автоматически – это назваемся метафункциональным продвижением (пересылкой).

Мы не должны здесь писать typename (фактически, это было бы нарушением), потому что компилятор знает, что зависимые имена в списке инициализации apply должны быть базовыми классами. Это фундамнтальное упрощение широко используется в MPL. Класс метафункции plus_f может быть исправлен аналогично.

Пользователи компиляторов основанных на EDG должны проверить документацию о работе метафункций. Проверить компилятор EDG, можно директивой __ EDG_VERSION __, который определен всеми EDG-компиляторами.

cout << __EDG_VERSION__ << endl;

MPL предоставляет передачи метафункций. Вместо того, чтобы строить целый класс метафункции, мы можем использовать mpl::transform следующим образом:

typename mpl::transform<D1, D2, mpl::minus<_1,_2>>::type

Аргументы (_1 и _2) являются заполнителями (placeholders, находятся в mpl::placeholders), и они позволяют сделать из имени метафункции minus полноценный тип, который должен принимать какие-то целые значения.

Применим заполнители к операторам деления:

template <class T, class D1, class D2>

quantity<

T,

typename mpl::transform<D1, D2, mpl::minus<_1,_2>>::type

>

operator/(quantity<T,D1> x, quantity<T,D2> y)

{

typedef typename

mpl::transform<D1,D2,mpl::minus<_1,_2>>::type dim;

return quantity<T,dim>( x.value() / y.value() );

}

Этот код проще, но можно упростить еще больше, поместив расчет размерности в отдельную метафункцию:

template <class D1, class D2>

struct divide_dimensions

: mpl::transform<D1,D2,mpl::minus<_1,_2>> // forwarding again

{};

template <class T, class D1, class D2>

quantity<T, typename divide_dimensions<D1,D2>::type>

operator/(quantity<T,D1> x, quantity<T,D2> y)

{

return quantity

<

T,

typename divide_dimensions<D1,D2>::type

>(x.value() / y.value());

}

Теперь можно выполнить обратный расчет: «действие силы на ноутбук»:

quantity<float,mass> m2 = f/a;

float rounding_error = std::abs((m2 - m).value());

Все, rounding_error должно быть очень близки к нолю. Такие вычисления могут разрушить целую программу. Если бы мы написали a/f вместо f/a, была бы ошибка компиляции, препятствуя ошибке размножиться всюду по нашей программе – в этом и заключается сила статической проверки.

Пример:

#include "Agatis.Dimension.h"

int main()

{

using namespace boost::mpl;

using namespace dimension;

quantity<float, mass> m(5.0f);

quantity<float, acceleration> a(9.8f);

auto f = (m * a);

cout << "force = " << f.value() << endl;

quantity<float,mass> m2 = f/a;

float rounding_error = abs((m2 - m).value());

cout << "mass2 = " << m2.value() << endl;

return 0;

}

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