dimensional

This parameterized type allows you to create a dimentional or "unit-ed" quantity. For example, you can create a distance type. The following comparison shows the differences between using dimensional and using a simple typedef.
typedef dimensional
typedef double distance; double dist_base= 1.0;
typedef dimensional<double,&dist_base> distance;
extern const distance Meter= distance::unit();
Pretty simple. huh?
distance is a synonym for double. distance is a unique type, so may be overloaded against double and other dimensional types. E.g.
void print (distance);
void print (time);
You can use any number where a distance is needed.
distance length= 5.14;
You cannot use a dimensionless number where a distance is expected. You must specify your units.
distance length= 5.14 * Meter;
You can do anything you want with a distance. The compiler allows only meaningful operations: you can't add distance and time together, for example.
The following sections goes into these topics in detail, roughly in the opposite order.

Restricted Operations

A dimensional double is not a double, but a distinct type. By default, you can only do a few operations on a dimensional type, as opposed to everything you can do with a double. Specifically, These simple operations are inherent in what it means to be a dimensional quantity, so are universal. If you have more operations on your specific type, add them as non-members. In particular, you can define operators to allow mixing of dimensions. For example, define multiplication of two distances to produce an area, and division of distance by time to produce a velocity.

Specify Your Units!

One particular maintainance problem in code is the implicit use of units. Most programs have values that implicitly hold some particular unit.
int timeout= 10000;
It's implicit because of how this value is used that the value 10000 means ten seconds. It has this meaning because the integer argument to Sleep is treated as a number of milliseconds, and this value is eventually passed to Sleep.

This is particularly a problem when different places use different units. If this same value were passed to SetWaitableTimer, for example, it would mean something different, since that function takes an integer representing 100-nanosecond intervals.

A fundimental principle of the dimensional type is that you can not assign a number to it. There is no way to simply turn a number into a dimensional value. You must specify your units. There is no special operator to do this—you simply multiply your value by a known dimensional quantity.

time timeout1= 10*seconds;
time timeout2= 10000*microseconds;
distance len1= 3.14* Meter;
distance len2= 8*Foot + 3*Inch;

To get a number out, the same principle is used. Divide by a known unit, and you will get a dimensionless number.

int t1= timeout / seconds;  //get value in seconds
int t2= timeout / microseconds;  //get value in microseconds

Additionally, a derived type may add member functions for obtaining values more efficiently (division is a rather expensive operation, compared with other CPU primitives). This allows efficient access to the value while still hiding the underlying representation.

extern const int time_base= 1;

class duration : public dimensional<int,&time_base> {
public:
   int as_milliseconds() const { return Value; }
   int as_seconds() const { return Value/1000; }
   };

extern const millisecond= duration::unit();
extern const second= millisecond*1000;

Creating Dimensional Types

Creating your own dimensional type requires more training than simply using existing ones, which is why this topic is last instead of first.

Generally, it is done with three lines of code. Let's take a closer look at the distance example.
double dist_base= 1.0;
typedef dimensional<double,&dist_base> distance;
extern const distance Meter= distance::unit();
The first line serves two purposes. The fundimental need for it concerns the template mechanism in C++. If you just declared distance to be a dimensional<double>, it would in fact be the same type as every other dimensional<double>, that was declared. This pretty much would defeat the purpose of having it as opposed to a simple typedef. So, a mechanism is needed to make a distinct type.

This is done by using a second, non-type, template parameter. Different values for the second argument will result in different specializations of the template and distinct types. The simplest way to get a unique value and track it across multiple compilation units is to use the address of a global variable.

Now, as long as that parameter is there, it can be co-opted for another purpose. Where does the first dimensional value come from? There is no way to turn a plain number into a distance other than to multiply it by an already known distance. So where does the first one come from?

This brings us to the third line. The static member unit returns a dimensional value of that type. Being a member, it can do things with the class that you can't, so it can get around the chicken-and-egg problem quite easily. The underlying value inside that object is the value found in the first line. It doesn't have to be 1.0. In general, it's whatever you want the representation of your base unit to be.

Once the first unit exists, you can declare other units in terms of the existing ones.

extern const distance Millimeter= Meter/1000;
extern const distance Inch= 25.4*Millimeter;
extern const distance Foot= 12.000024*Inch;