Lo?c Henry-Gr?ard wrote:

> Hi,

>

> I'm using a homebrew, lightweight version of SIunits, the physical

> dimension checker. For example I define types such as m (meters), s

> (seconds) and mps (meters per second) in namespace SI and I have all

> the overloadings of operator* such as

>

> SI::m operator* (SI::s, SI::mps)

> { ... }

>

> saying that a velocity multiplied by a time yields a distance.

>

> On the other hand, before I had implemented the dimension checking, I

> was using a generic three dimension vector type with an operator*

>

> vec<T1> operator* (T2 a, vec<T1> b) { return vec<T1> (b.x * a, b.y *

> a, b.z * a) ; }

>

> Now of course if I cannot multiply a time by a vector of speeds and

> automatically get a vector

> of distances, since the template tries to instanciate

>

> vec<SI::mps> operator* (SI::s a, vec<SI::mps> b)

>

> which is not dimensionally correct.

>

> I'm not familiar with the full-blown implementation of SIunits, even

> though I use the same basic idea of a template parameterized by ints

> giving the exponent of the unit in each dimension.

> I don't know if their implementation allows an elegant implementation

> of a generic vector class that would work transparently for normal

> scalar types and for dimension-checked units, e.g.

> that would implement

>

> vec<SI::m> operator* (SI::s, vec<SI::mps>)

>

> But since my problem looks quite common I thought someone might have

> an idea of the most elegant way to do that.
Well, the most straight-forward way would be to specialize each operator

for all possible argument types. A more sophisticated approach would be

to define a traits template, specialized for each possible pair of

argument types. I've posted code below to show the idea; this is

absurdly simple, and I'm not familiar with the "SIunits" package to

begin with, so don't think I'm implying this code is production-worthy.

It should at least compile, though, and that ought to prove the

point.

namespace SI

{

struct s { int value; s( int v =0 ): value( v ) { } };

struct m { int value; m( int v =0 ): value( v ) { } };

struct mps { int value; mps( int v =0 ): value( v ) { } };

template< typename T > struct vec

{

T x, y, z;

vec( T const& ax, T const& ay, T const& az ):

x( ax ), y( ay ), z( az ) { }

};

template< typename T, typename U > struct Traits { };

template< > struct Traits< s, mps > { typedef m Product_Type; };

template< typename T, typename U >

typename Traits< T, U >:

roduct_Type

operator * ( T const& a, U const& b )

{

typename Traits< T, U >:

roduct_Type result;

result.value = a.value * b.value;

return result;

}

template< typename T, typename U >

vec< typename Traits< T, U >:

roduct_Type >

operator * ( T const& a, vec< U > const& b )

{

return vec< typename Traits< T, U >:

roduct_Type >(

a * b.x, a * b.y, a * b.z );

}

}

int main( )

{

SI::s s;

SI::mps mps;

SI::vec< SI::mps > mpsvec( 3, 4, 5 );

SI::m m = s * mps;

SI::vec< SI::m > mvec = s * mpsvec;

}