...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 / Representing Dimensions |

An international standard called *SystÃ¨me
International d'Unites* (SI), breaks every quantity down into a
combination of the dimensions *mass*, *length* (or *position*),
*time*, *charge*, *temperature*, *intensity*, and *angle*. To be
reasonably general, our system would have to be able to
represent seven or more fundamental dimensions. It also needs
the ability to represent composite dimensions that, like *force*,
are built through multiplication or division of the fundamental
ones.

In general, a composite dimension is the product of powers of
fundamental dimensions. [1] If we were going to represent
these powers for manipulation at runtime, we could use an array of
seven `int`s, with each position in the array holding the power
of a different fundamental dimension:

typedef int dimension[7]; // m l t ... dimension const mass = {1, 0, 0, 0, 0, 0, 0}; dimension const length = {0, 1, 0, 0, 0, 0, 0}; dimension const time = {0, 0, 1, 0, 0, 0, 0}; ...

[1] | Divisors just contribute negative exponents, since
1/x = x^{-1}. |

In that representation, force would be:

dimension const force = {1, 1, -2, 0, 0, 0, 0};

that is, *mlt*^{-2}. However, if we want to get dimensions into the
type system, these arrays won't do the trick: they're all
the same type! Instead, we need types that *themselves* represent
sequences of numbers, so that two masses have the same type and a
mass is a different type from a length.

Fortunately, the MPL provides us with a collection of **type
sequences**. For example, we can build a sequence of the built-in
signed integral types this way:

#include <boost/mpl/vector.hpp> typedef boost::mpl::vector< signed char, short, int, long> signed_types;

How can we use a type sequence to represent numbers? Just as
numerical metafunctions pass and return wrapper *types* having a
nested `::value`, so numerical sequences are really sequences of
wrapper types (another example of polymorphism). To make this sort
of thing easier, MPL supplies the `int_<N>` class template, which
presents its integral argument as a nested `::value`:

#include <boost/mpl/int.hpp> namespace mpl = boost::mpl; // namespace alias static int const five = mpl::int_<5>::value;

In fact, the library contains a whole suite of integral constant
wrappers such as `long_` and `bool_`, each one wrapping a
different type of integral constant within a class template.

Now we can build our fundamental dimensions:

typedef mpl::vector< mpl::int_<1>, mpl::int_<0>, mpl::int_<0>, mpl::int_<0> , mpl::int_<0>, mpl::int_<0>, mpl::int_<0> > mass; typedef mpl::vector< mpl::int_<0>, mpl::int_<1>, mpl::int_<0>, mpl::int_<0> , mpl::int_<0>, mpl::int_<0>, mpl::int_<0> > length; ...

Whew! That's going to get tiring pretty quickly. Worse, it's hard
to read and verify: The essential information, the powers of each
fundamental dimension, is buried in repetitive syntactic "noise."
Accordingly, MPL supplies **integral sequence wrappers** that allow
us to write:

#include <boost/mpl/vector_c.hpp> 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; // or position 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;

Even though they have different types, you can think of these
`mpl::vector_c` specializations as being equivalent to the more
verbose versions above that use `mpl::vector`.

If we want, we can also define a few composite dimensions:

// base dimension: m l t ... typedef mpl::vector_c<int,0,1,-1,0,0,0,0> velocity; // l/t typedef mpl::vector_c<int,0,1,-2,0,0,0,0> acceleration; // l/(t^{2}) typedef mpl::vector_c<int,1,1,-1,0,0,0,0> momentum; // ml/t typedef mpl::vector_c<int,1,1,-2,0,0,0,0> force; // ml/(t^{2})

And, incidentally, the dimensions of scalars (like pi) can be described as:

typedef mpl::vector_c<int,0,0,0,0,0,0,0> scalar;