SIunits-style dimension checking and vectors

Discussion in 'C++' started by Lo?c Henry-Gr?ard, Dec 28, 2003.

  1. 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.
     
    Lo?c Henry-Gr?ard, Dec 28, 2003
    #1
    1. Advertising

  2. Lo?c Henry-Gr?ard

    Jeff Schwab Guest

    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 >::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;
    }
     
    Jeff Schwab, Dec 28, 2003
    #2
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Ben Ingram
    Replies:
    6
    Views:
    393
    red floyd
    Jan 30, 2004
  2. Replies:
    3
    Views:
    700
    Shadowman
    Mar 26, 2008
  3. Luuk
    Replies:
    15
    Views:
    829
    Nobody
    Feb 11, 2010
  4. Ken Varn
    Replies:
    0
    Views:
    470
    Ken Varn
    Apr 26, 2004
  5. Guest
    Replies:
    0
    Views:
    444
    Guest
    Sep 14, 2005
Loading...

Share This Page