...one of the most highly
regarded and expertly designed C++ library projects in the
world.

— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards

Front Page / Tutorial: Metafunctions and Higher-Order Metaprogramming / Dimensional Analysis / 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> structdivide_dimensions: mpl::transform<D1,D2,mpl::minus<_1,_2> > // forwarding again {}; template <class T, class D1, class D2> quantity<T, typenamedivide_dimensions<D1,D2>::type> operator/(quantity<T,D1> x, quantity<T,D2> y) { return quantity<T, typenamedivide_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.