SIunits-style dimension checking and vectors

L

Lo?c Henry-Gr?ard

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.
 
J

Jeff Schwab

Lo?c Henry-Gr?ard said:
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 >::product_Type
operator * ( T const& a, U const& b )
{
typename Traits< T, U >::product_Type result;
result.value = a.value * b.value;
return result;
}

template< typename T, typename U >
vec< typename Traits< T, U >::product_Type >
operator * ( T const& a, vec< U > const& b )
{
return vec< typename Traits< T, U >::product_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;
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,566
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top