THE BOOST MPL LIBRARY: Implementing Division

Front Page / Tutorial: Metafunctions and Higher-Order Metaprogramming / Dimensional Analysis / Implementing Division

# Implementing Division

Division is similar to multiplication, but instead of adding exponents, we must subtract them. Rather than writing out a near duplicate of `plus_f`, we can use the following trick to make `minus_f` much simpler:

    struct minus_f
    {
        template <class T1, class T2>
        struct apply
          : mpl::minus<T1,T2> {};
    };

Here `minus_f::apply` uses inheritance to expose the nested `type` of its base class, `mpl::minus`, so we don't have to write:

    typedef typename ...::type type

We don't have to write `typename` here (in fact, it would be illegal), because the compiler knows that dependent names in `apply`'s initializer list must be base classes. [2] This powerful simplification is known as metafunction forwarding; we'll apply it often as the book goes on. [3]

[2] | In case you're wondering, the same approach could have been applied to `plus_f`, but since it's a little subtle, we introduced the straightforward but verbose formulation first.

[3] | Users of EDG-based compilers should consult the book's Appendix C for a caveat about metafunction forwarding. You can tell whether you have an EDG compiler by checking the preprocessor symbol `__EDG_VERSION__`, which is defined by all EDG-based compilers.

Syntactic tricks notwithstanding, writing trivial classes to wrap existing metafunctions is going to get boring pretty quickly. Even though the definition of `minus_f` was far less verbose than that of `plus_f`, it's still an awful lot to type. Fortunately, MPL gives us a much simpler way to pass metafunctions around. Instead of building a whole metafunction class, we can invoke `transform` this way:

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

Those funny looking arguments (`_1` and `_2`) are known as placeholders, and they signify that when the `transform`'s `BinaryOperation` is invoked, its first and second arguments will be passed on to `minus` in the positions indicated by `_1` and `_2`, respectively. The whole type `mpl::minus<_1,_2>` is known as a placeholder expression.

Note

MPL's placeholders are in the `mpl::placeholders` namespace and defined in `boost/mpl/placeholders.hpp`. In this book we will usually assume that you have written:

    #include<boost/mpl/placeholders.hpp>
    using namespace mpl::placeholders;

so that they can be accessed without qualification.

Here's our division operator written using placeholder expressions:

    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() );
    }

This code is considerably simpler. We can simplify it even further by factoring the code that calculates the new dimensions into its own metafunction:

    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());
    }

Now we can verify our "force-on-a-laptop" computation by reversing it, as follows:

    quantity<float,mass> m2 = f/a;
    float rounding_error = std::abs((m2 - m).value());

If we got everything right, `rounding_error` should be very close to zero. These are boring calculations, but they're just the sort of thing that could ruin a whole program (or worse) if you got them wrong. If we had written `a/f` instead of `f/a`, there would have been a compilation error, preventing a mistake from propagating throughout our program.