// (by Ariel Badichi) #include <iostream>
#include <boost/static_assert.hpp> #include <boost/mpl/vector_c.hpp> #include <boost/mpl/transform.hpp> #include <boost/mpl/placeholders.hpp> #include <boost/mpl/plus.hpp> #include <boost/mpl/equal.hpp> #include <boost/mpl/minus.hpp>
namespace mpl = boost::mpl; using namespace mpl::placeholders;
typedef mpl::vector_c<int, 1, 0, 0, 0, 0, 0, 0> mass; typedef mpl::vector_c<int, 0, 1, 0, 0, 0, 0, 0> length; typedef mpl::vector_c<int, 0, 0, 1, 0, 0, 0, 0> time; typedef mpl::vector_c<int, 0, 0, 0, 1, 0, 0, 0> charge; typedef mpl::vector_c<int, 0, 0, 0, 0, 1, 0, 0> temperature; typedef mpl::vector_c<int, 0, 0, 0, 0, 0, 1, 0> intensity; typedef mpl::vector_c<int, 0, 0, 0, 0, 0, 0, 1> angle;
typedef mpl::vector_c<int, 0, 1,-1, 0, 0, 0, 0> velocity; typedef mpl::vector_c<int, 0, 1,-2, 0, 0, 0, 0> acceleration; typedef mpl::vector_c<int, 1, 1,-1, 0, 0, 0, 0> momentum; typedef mpl::vector_c<int, 1, 1,-2, 0, 0, 0, 0> force;
typedef mpl::vector_c<int, 0, 0, 0, 0, 0, 0, 0> scalar;
template<typename T, typename Dimensions> class quantity { public: explicit quantity(T x) : m_value(x) {}
template<typename OtherDimensions?> quantity(quantity<T, OtherDimensions?> q) : m_value(q.value()) { BOOST_STATIC_ASSERT((mpl::equal<Dimensions, OtherDimensions?>::type::value)); }
T value() const { return m_value; }
private: T m_value; };
// We need the static asserts in operator+/operator- so even expressions that // are not converted into a target quantity type, like: // a + m; // won't compile.
template<typename T, typename D1, typename D2> quantity<T, D1> operator+ (quantity<T, D1> q1, quantity<T, D2> q2) { BOOST_STATIC_ASSERT((mpl::equal<D1, D2>::type::value)); return quantity<T, D1>(q1.value() + q2.value()); }
template<typename T, typename D1, typename D2> quantity<T, D1> operator- (quantity<T, D1> q1, quantity<T, D2> q2) { BOOST_STATIC_ASSERT((mpl::equal<D1, D2>::type::value)); return quantity<T, D1>(q1.value() - q2.value()); }
template<typename D1, typename D2> struct multiply_dimensions : mpl::transform<D1, D2, mpl::plus<_, _> > {};
template<typename T, typename D1, typename D2> quantity<T, typename multiply_dimensions<D1, D2>::type> operator* (quantity<T, D1> q1, quantity<T, D2> q2) { typedef typename multiply_dimensions<D1, D2>::type dim; return quantity<T, dim>(q1.value() * q2.value()); }
template<typename D1, typename D2> struct divide_dimensions : mpl::transform<D1, D2, mpl::minus<_, _> > {};
template<typename T, typename D1, typename D2> quantity<T, typename divide_dimensions<D1, D2>::type> operator/ (quantity<T, D1> q1, quantity<T, D2> q2) { typedef typename divide_dimensions<D1, D2>::type dim; return quantity<T, dim>(q1.value() / q2.value()); }
template<typename S, typename T, typename D> S & operator<< (S & out, quantity<T, D> q) { return out << q.value(); }
int main() { quantity<float, mass> m(1.5f); quantity<float, acceleration> a(9.8f);
quantity<float, mass> m2(0.5f); m = m + m2;
quantity<float, force> f(1.0f);
f = f + m * a; std::cout << "f = " << f << "\n";
quantity<float, acceleration> a2 = f / m;
return 0; }