![]() |
![]() ![]() ![]() ![]() ![]() |
![]() |
THE BOOST MPL LIBRARY: Implementing MultiplicationBoost , ,
|
Front Page / Tutorial: Metafunctions and Higher-Order Metaprogramming / Dimensional Analysis / Implementing Multiplication |
Умножение немного сложнее, чем сложение и вычитание. До сих пор размеры аргументов и результатов были одинаковыми, но при умножении результат обычно будет иметь разные размеры от любого из аргументов. Для умножения отношение:
(xa)(xb) == x (a + b)
Это означает, что экспоненты измерений результата должны быть суммой соответствующих экспонентов из измерений аргумента. Разделение аналогично, за исключением того, что сумма заменяется разницей.
Для объединения соответствующих элементов из двух последовательностей мы будем использовать преобразование MPL.алгоритм.Преобразованиеявляется метафункцией, которая итерирует через две входные последовательности параллельно, передавая элемент из каждой последовательности в произвольную двоичную метафункцию и помещая результат в выходную последовательность.
template <class Sequence1, class Sequence2, class BinaryOperation> struct transform; // returns a Sequence
Приведенная выше подпись должна выглядеть знакомой, если вы знакомы с алгоритмом преобразования STL, который принимает двепоследовательности выполненияв качестве входов:
template < class InputIterator1, class InputIterator2 , class OutputIterator, class BinaryOperation > void transform( InputIterator1 start1, InputIterator2 finish1 , InputIterator2 start2 , OutputIterator result, BinaryOperation func);
Теперь нам просто нужно пройти.Бинарная операция, которая добавляет или вычитает, чтобы умножить или разделить размеры сmpl:: преобразовать. Если вы посмотритесправочное руководство по MPL, вы увидитеплюсиминусметафункции, которые делают именно то, что вы ожидаете:
#include <boost/static_assert.hpp> #include <boost/mpl/plus.hpp> #include <boost/mpl/int.hpp> namespace mpl = boost::mpl; BOOST_STATIC_ASSERT(( mpl::plus< mpl::int_<2> , mpl::int_<3> >::type::value == 5 ));
На данный момент может показаться, что у нас есть решение, но мы еще не совсем там. Наивная попытка применить алгоритм преобразованияв реализации оператора*приводит к ошибке компилятора:
#include <boost/mpl/transform.hpp> template <class T, class D1, class D2> quantity< T , typename mpl::transform<D1,D2,mpl::plus>::type > operator*(quantity<T,D1> x, quantity<T,D2> y) { ... }
Это не удается, потому что протокол говорит, что аргументы метафункции должны быть типами, иплюсне тип, а шаблон класса. Каким-то образом нам нужно сделать метафункции, такие какплюс, соответствующими форме метаданных.
Одним из естественных способов введения полиморфизма между метафункциями и метаданными является использование идиомы обертки, которая дала нам полиморфизм между типами и интегральными константами. Вместо вложенной интегральной константы можно использовать шаблон класса, вложенный вкласс метафункций:
struct plus_f { template <class T1, class T2> struct apply { typedef typename mpl::plus<T1,T2>::type type; }; };
Definition
А.Класс метафункций— это класс с общедоступной вложенной метафункцией, называемой.
В то время как метафункция является шаблоном, но не типом, класс метафункций обертывает этот шаблон в обычный класс, которыйявляетсятипом. Поскольку метафункции работают на типах возврата, класс метафункции может быть передан в качестве аргумента другой метафункции.
Наконец, у нас есть.Тип бинарной операции, который мы можем перейти кпреобразованиюбез возникновения ошибки компиляции:
template <class T, class D1, class D2> quantity< T , typename mpl::transform<D1,D2,plus_f>::type // new dimensions > operator*(quantity<T,D1> x, quantity<T,D2> y) { typedef typename mpl::transform<D1,D2,plus_f>::type dim; return quantity<T,dim>( x.value() * y.value() ); }
Теперь, если мы хотим вычислить силу, выдаваемую гравитацией на 5-килограммовом портативном компьютере, это просто ускорение из-за силы тяжести (9,8 м / сек2), умноженное на массу ноутбука:
quantity<float,mass> m(5.0f); quantity<float,acceleration> a(9.8f); std::cout << "force = " << (m * a).value();
Нашоператор*умножает значения времени выполнения (что приводит к 6.0f), и наш код метапрограммы используетпреобразованиедля суммирования метапоследовательности экспонент фундаментального измерения, так что тип результата содержит представление нового списка экспонентов, что-то вроде:
mpl::vector_c<int,1,1,-2,0,0,0,0>
Однако, если мы попытаемся написать:
quantity<float,force> f = m * a;
Мы столкнемся с небольшой проблемой. Хотя результатm*aдействительно представляет силу с показателями массы, длины и времени 1, 1, и -2 соответственно, тип, возвращаемыйпреобразованием, не является специализациейвектора_c. Вместо этогопреобразованиеработает в общем на элементах его входов и строит новую последовательность с соответствующими элементами: тип со многими из тех же свойств последовательности, что иmpl::vector_c< ;int,1,1,-2,0,0,0,0>, но с другим типом C++ в целом. Если вы хотите увидеть полное имя типа, вы можете попытаться составить пример самостоятельно и посмотреть сообщение об ошибке, но точные детали не важны. Дело в том, чтосилаименует другой тип, поэтому назначение выше не удастся.
Чтобы решить проблему, мы можем добавить неявное преобразование из типа результата умножения вколичество
template <class T, class Dimensions> struct quantity { // converting constructor template <class OtherDimensions> quantity(quantity<T,OtherDimensions> const& rhs) : m_value(rhs.value()) { } ...
К сожалению, такое общее обращение подрывает всю нашу цель, допуская такие глупости, как:
// Should yield a force, not a mass! quantity<float,mass> bogus = m * a;
Мы можем исправить эту проблему, используя другой алгоритм MPL,равный, который проверяет, что две последовательности имеют одинаковые элементы:
template <class OtherDimensions> quantity(quantity<T,OtherDimensions> const& rhs) : m_value(rhs.value()) { BOOST_STATIC_ASSERT(( mpl::equal<Dimensions,OtherDimensions>::type::value )); }
Теперь, если размеры двух величин не совпадают, утверждение вызовет ошибку компиляции.
Статья THE BOOST MPL LIBRARY: Implementing Multiplication раздела может быть полезна для разработчиков на c++ и boost.
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.
:: Главная :: ::
реклама |