Navigation:
A match made in heaven:
C++ is uniquely suited to tackle the problems posed by Dimenso without need for code generation. The concept of interrelated types that refer to one another can be represented entirely by a template, parameterized by the dimension exponents. There is no limit to the number of dimensions that can be represented, since only template instantiations that are used in the project will be found in the executable.

Using DimensionedValue looks and feels close to the habitual use of units and dimensions. length length1=10*inch; length length2=3*centi*meter; mass m=10*kilogram; // "kilogram" is optional acceleration g=9.81; // same as 9.81*meter/(second*second) force f=m*g; Outputting and conversion to specific units is very easy. cout << length1 << endl; cout << length1 / feet << " in feet" << endl;
The code:
The code is available as a C++ header file. The main class is DimensionedValue. Notice the straightforward way that dimensions for the resulting type of each operation are calculated. template <int L, int M, int T, int C>; class DimensionedValue { double v; public: DimensionedValue(double val) : v(val) {} inline double magnitude() { return v; } template<int L2, int M2, int T2, int C2> DimensionedValue<L+L2,M+M2,T+T2,C+C2> operator*(DimensionedValue<L2,M2,T2,C2> other) { return DimensionedValue<L+L2,M+M2,T+T2,C+C2>( magnitude()*other.magnitude() ); } template<int L2, int M2, int T2, int C2> DimensionedValue<L-L2,M-M2,T-T2,C-C2> operator/(DimensionedValue<L2,M2,T2,C2> other) { return DimensionedValue<L-L2,M-M2,T-T2,C-C2>( magnitude()/other.magnitude() ); } DimensionedValue operator+(DimensionedValue other) { return DimensionedValue(magnitude()+other.magnitude()); } DimensionedValue operator-(DimensionedValue other) { return DimensionedValue(magnitude()-other.magnitude()); } void printOn(ostream& os) { os<<magnitude()<<' '; DimensionedUnit<L,M,T,C>::printOn(os); } bool unitsAreDerived() { return DimensionedUnit<L,M,T,C>::unitsAreDerived(); } static const int mExponent; static const int kExponent; static const int sExponent; static const int aExponent; }; template <int L, int M, int T, int C> const int DimensionedValue<L,M,T,C>::mExponent = L; template <int L, int M, int T, int C> const int DimensionedValue<L,M,T,C>::kExponent = M; template <int L, int M, int T, int C> const int DimensionedValue<L,M,T,C>::sExponent = T; template <int L, int M, int T, int C> const int DimensionedValue<L,M,T,C>::aExponent = C; template <int L, int M, int T, int C> static ostream& operator<<( ostream& os, DimensionedValue<L,M,T,C> u) { u.printOn(os); return os; } template <int L, int M, int T, int C> static DimensionedValue<L,M,T,C> operator*(double d,DimensionedValue<L,M,T,C> u) { return DimensionedValue<L,M,T,C>(d*u.magnitude()); } DimensionedUnit is a helper class that outputs the string representation of the units. template <int L, int M, int T, int C> class DimensionedUnit { static bool printUnit( bool showDot, ostream& os, char* unit, int dim) { if(dim!=0) { if(showDot) { os<<'\xb7'; } os<<unit; if(dim!=1) { os<<dim; } showDot=true; } return showDot; } public: static void printOn(ostream& os) { bool showDot=false; showDot = printUnit(showDot,os,"m",L); showDot = printUnit(showDot,os,"Kg",M); showDot = printUnit(showDot,os,"s",T); printUnit(showDot,os,"A",C); } static bool unitsAreDerived() { return false; } }; It uses template specialization to override the default behavior for standard units. template<> struct DimensionedUnit<0,0,-1,0> { static void printOn(ostream& os) { os<<"Hz"; } static bool unitsAreDerived() { return true; } }; . . . The standard types are defined as typedefs. A special case was made for "time" since it conflicted with a function defined in "time.h". The type was named "time_". typedef DimensionedValue<0,0,0,0> unity; typedef DimensionedValue<1,0,0,0> length; typedef DimensionedValue<0,1,0,0> mass; . . . typedef DimensionedValue<0,0,1,1> charge; . . . The standard units are defined as values. When multiplied by numbers, they yield dimensioned values of the appropriate dimension. const length meter=1; const length inch=0.0254; const length foot=12*inch; const length feet=foot; const length yard=3*feet; const length mile=5280*feet; . . . For convenience, the standard SI qualifiers are also defined as values. They can be multiplied by units to yield "qualified units", e.g. kilo*newton. const double yotta=1e24; const double zetta=1e21; const double exa=1e18; . . .
Conventional names:
expectedactual
m1k0s0a0length
m2k0s0a0area
m3k0s0a0volume
m1k0s_1a0velocity
m1k0s_2a0acceleration
m0k1s0a0mass
m0k0s0a0time
m1k1s_1a0momentum
m2k1s_1a0angular
_momentum
m0k0s_1a0frequency
m1k1s_2a0force
m_1k1s_2a0pressure
m_1k1s_1a0viscosity
m2k1s_2a0energy
m2k1s_3a0power
m0k0s1a1charge
m2k1s_3a_1potential
m_2k_1s4a2capacitance
m2k1s_3a_2resistance
m_2k_1s3a2conductance
m2k1s_2a_1magnetic_flux
m0k1s_2a_1magnetic_flux
_density
m2k1s_2a_2inductance

Not all types exist in the standard download, because the bounds it was built with exclude some of them.

Derived Units:
expectedderived
s-1Hz
m·kg·s-2N
m-1·kg·s-2Pa
m-1·kg·s-1Pa·s
(Poiseuille)
m2·kg·s-2J
m2·kg·s-3W
s·AC
m2·kg·s-3·A-1V
m-2·kg-1·s4·A2F
m2·kg·s-3·A-2Ohm
m-2·kg-1·s3·A2S
m2·kg·s-2·A-1Wb
kg·s-2·A-1T
m2·kg·s-2·A-2H

Not all cases exist in the standard download, because the bounds it was built with exclude some of the types.

© 2007 Dimitrios Souflis (dsouflis at acm dot org) - Original template by Salis @ progranimation.com