I recently read a series in C ++ Source, "A Pause to Reflect: Five Lists of Five". In Part V, Scott Meyers discusses the solution to Barton and Nackman with the unit problem. Being a software engineer for the aerospace industry, this Aha! The moment turned me on. Until now, Ive not heard of this approach (and these authors).
I did a study trying to find more information about the solution. I came across this presentation here: http://se.ethz.ch/~meyer/publications/OTHERS/scott_meyers/dimensions.pdf
I think I understand everything that I read about this decision. But I feel that part of the puzzle is missing. Nowhere is this beautiful, elegant solution suitable. In particular, I am interested in transformations that are more than just a multiplication factor. For example, temperature conversion between Kelvin, Celsus and Fahrenheit. I would like to be able to use these temperatures interchangeably.
My questions:
Did I miss something? Is the scale being discussed somewhere in relation to the discussion of the Units solution that I missed?
If not, how can I approach this problem further? Is there an existing model that can be used in conjunction with the B & N approach to complete the solution?
My goal is to have code that looks like the example below without excessive computation. In the case of distance, I want to be able to declare an object defined as a mile and do all my corresponding calculations as miles, without having to constantly convert back and forth to counters.
Example:
typedef Units<double, miles> uMiles; typedef Units<double, kilometers> uKilometers; uMiles d1 (1.0); uKilometers d2 (1.60934); d1 += d2; if (d1.val(miles) == 2.0)
Note: I saw a solution to the BOOST UNITS problem, and I don't like it. For me it is very impenetrable. I am also not allowed to use external libraries such as boost.
Backup Data:
Unit class as described:
template<class T, // Precision int m, // Mass int l, // Length int t, // Time int q, // Charge int k, // Temperature int i, // Luminous Intensity int a> // Angle class Units { public: // ------------------------------------------------------ explicit Units (T initVal = 0) : val (initVal) { } // -------------------------------------------------------------------- // Operator: Assignment from type T Units<T, m, l, t, q, k, i, a>& operator= (const T rhs) { val = rhs; return *this; } // -------------------------------------------------------------------- // Operator: Type Converstion to T operator T () const { return val; } // -------------------------------------------------------------------- // Operator: += Units<T, m, l, t, q, k, i, a>& operator+= (const Units<T, m, l, t, q, k, i, a>& rhs) { val += rhs.val; return *this; } // -------------------------------------------------------------------- Units<T, m, l, t, q, k, i, a>& operator-= (const Units<T, m, l, t, q, k, i, a>& rhs) { val -= rhs.val; return *this; } // -------------------------------------------------------------------- Units<T, m, l, t, q, k, i, a>& operator*= (T rhs) { val *= rhs; return *this; } // -------------------------------------------------------------------- Units<T, m, l, t, q, k, i, a>& operator/= (T rhs) { val /= rhs; return *this; } // -------------------------------------------------------------------- // Get Reference T& Val () { return val; } // -------------------------------------------------------------------- // Get Value const T& Val () const { return val; } private: T val; }; // ---------------------------------------------------------------------------- // Operator: Addition template<class T, int m, int d, int t, int q, int k, int i, int a> const Units<T, m, d, t, q, k, i, a> operator+ (const Units<T, m, d, t, q, k, i, a> & lhs, const Units<T, m, d, t, q, k, i, a> & rhs) { Units<T, m, d, t, q, k, i, a> result (lhs); return result += rhs; } // ---------------------------------------------------------------------------- // Operator: Subtraction template<class T, int m, int d, int t, int q, int k, int i, int a> const Units<T, m, d, t, q, k, i, a> operator- (const Units<T, m, d, t, q, k, i, a> & lhs, const Units<T, m, d, t, q, k, i, a> & rhs) { Units<T, m, d, t, q, k, i, a> result (lhs); return result -= rhs; } // ---------------------------------------------------------------------------- // Operator: Multiplication template<class T, int m, int d, int t, int q, int k, int i, int a> const Units<T, m, d, t, q, k, i, a> operator* (const Units<T, m, d, t, q, k, i, a> & lhs, const Units<T, m, d, t, q, k, i, a> & rhs) { Units<T, m, d, t, q, k, i, a> result (lhs); return result *= rhs; } // ---------------------------------------------------------------------------- // Operator: Division template<class T, int m, int d, int t, int q, int k, int i, int a> const Units<T, m, d, t, q, k, i, a> operator/ (const Units<T, m, d, t, q, k, i, a> & lhs, const Units<T, m, d, t, q, k, i, a> & rhs) { Units<T, m, d, t, q, k, i, a> result (lhs); return result /= rhs; } // ---------------------------------------------------------------------------- // Operator: Multiplication (Creates New Type) template<class T, int m1, int d1, int t1, int q1, int k1, int i1, int a1, int m2, int d2, int t2, int q2, int k2, int i2, int a2> // Return Type Units<T, m1 + m2, d1 + d2, t1 + t2, q1 + q2, k1 + k2, i1 + i2, a1 + a2> operator* (const Units<T, m1, d1, t1, q1, k1, i1, a1>& lhs, const Units<T, m2, d2, t2, q2, k2, i2, a2>& rhs) { // New Return type typedef Units<T, m1 + m2, d1 + d2, t1 + t2, q1 + q2, k1 + k2, i1 + i2, a1 + a2> ResultType; return ResultType (lhs.Val() * rhs.Val()); } // ---------------------------------------------------------------------------- // Operator: Division (Creates New Type) template<class T, int m1, int d1, int t1, int q1, int k1, int i1, int a1, int m2, int d2, int t2, int q2, int k2, int i2, int a2> // Return Type Units<T, m1 - m2, d1 - d2, t1 - t2, q1 - q2, k1 - k2, i1 - i2, a1 - a2> operator/ (const Units<T, m1, d1, t1, q1, k1, i1, a1>& lhs, const Units<T, m2, d2, t2, q2, k2, i2, a2>& rhs) { // New Return type typedef Units< T, m1 - m2, d1 - d2, t1 - t2, q1 - q2, k1 - k2, i1 - i2, a1 - a2> ResultType; return ResultType (lhs.Val() / rhs.Val()); }
This class allows us to write code that looks like this:
// Base Types typedef Units<double, 1,0,0,0,0,0,0> uMass; typedef Units<double, 0,1,0,0,0,0,0> uLength; typedef Units<double, 0,0,1,0,0,0,0> uTime; typedef Units<double, 0,0,0,1,0,0,0> uCharge; typedef Units<double, 0,0,0,0,1,0,0> uTemperature; typedef Units<double, 0,0,0,0,0,1,0> uIntensity; typedef Units<double, 0,0,0,0,0,0,1> uAngle; // Derived Types typedef Units<double, 0,2, 0,0,0,0,0> uArea; typedef Units<double, 0,3, 0,0,0,0,0> uVolume; typedef Units<double, 0,1,-1,0,0,0,0> uVelocity; typedef Units<double, 0,1,-2,0,0,0,0> uAcceleration; typedef Units<double, 1,1,-2,0,0,0,0> uForce; uMass mass; uTime time; uForce force; uLength length; uVelocity velocity; uAcceleration acceleration; // This will compile mass = 7.2; acceleration = 3.5; force = mass * acceleration; // These will not compile ** Enforcing Dimensional Unit Correctness force = 7.2 * acceleration; force = mass; force *= acceleration;