I had an idea motivated by some of the documentation I read in the tutorial of the boost MTL library.
The basic premise is that I would like to use templates to give me compile time type checking errors for things that are otherwise the same.
Namely, lets say I have two units of measurement, Radians and Degrees. The most obvious way to go about getting type safety is to define 2 classes:
struct Radian
{
float rad;
}
struct Degree
{
float deg;
}
This is all well and good, except I can do something like
func()
{
Radian r;
Degree d;
r.rad = d.deg;
}
It would be nice if I could flag an assignment like that as a compile time type error. This lead me to consider the following:
struct Degree {};
struct Radian {};
template <class Data, class Unit>
struct Quantity
{
Data val;
Quantity<Data,Unit>() : val() {}
explicit Quantity<Data,Unit>(Data v) : val(v) {}
};
typedef Quantity<float,Radian> Rad;
typedef Quantity<float,Degree> Deg;
Now, the equivalent code of func() using the types Rad and Deg would flag that assignment as a compile time error (and with explicit set, even doing something as simple as Rad r = 2.0 is considered a compile time error).
What I really want is a float that has this additional units property that can be used to catch logic errors at compile time (ie, using degrees in a function that expects radians), but for all intents and purposes, these things are floats.
As a general question, what are your thoughts on this approach? I am slightly concerned that this is the wrong way to achieve my goal, but it has a strange appeal. Also, is there a "trait" or something like boost concept check that I can use to determine that Data is "float like". Finally, is there any way I can inherit default implementations of operations such as "<<" so that I don't have to implement all of them manually in the Quantity class?