Boost logo

Boost :

From: Daryle Walker (darylew_at_[hidden])
Date: 2001-05-20 09:29:11


This class template is from the Special Function library under review.

The "quaternion.hpp" header has a big waste of writing and code space. The
specializations of the float, double, and long double versions are exactly
like the main version, except for explicitly (pardon the pun) mentioning
conversion constructors for the other special versions, and making some of
those constructors explicit (if it's from a higher type). I decided to be
naughty and make a base class that encapsulates the functionality, using
inheritance as a scanky code-sharing hack instead of for OO greatness. The
four versions of quaternion would inherit from quaternion_base with
(hopefully) inline forwarding methods.

Before I did that, I realized that quaternion_base could be abstracted
further, to another base class so a future 'octonion_base' could share code:

//=========================================================================
template < typename T, std::size_t LbN >
class boost::detail::binary_nion
{
    typedef binary_nion<T, LbN> self_type;

public:
    // Template parameters
    typedef T value_type;

    BOOST_STATIC_CONSTANT( std::size_t, lb_component_count = LbN );

    // More information
    BOOST_STATIC_CONSTANT( std::size_t, component_count = (1ul << LbN) );

    // Constructors (use automatic destructor and copy constructor)
    explicit binary_nion( value_type const &same_initializer = T() );

    #ifndef BOOST_NO_MEMBER_TEMPLATES
    template < typename U, std::size_t LbM >
    explicit binary_nion( binary_nion<U, LbM> const &copied );
    #endif

    // Operations
    void swap( self_type &b );

    // Operators (use automatic regular assignment)
    bool operator ==( self_type const &other ) const;

#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
private:
    template < typename U, std::size_t LbM > friend class binary_nion<U,
LbM>;
#endif

    // Data accessors
    T * begin();
    T * end();

    T const * begin() const;
    T const * end() const;
                
protected:
    // Member data
    value_type data_[ component_count ];

};
//=========================================================================

I made up the "binary_nion" name, do you know the official general name of
quaternions, octonions, etc.?

Now I can work on quaternion_base:

//=========================================================================
template < typename T >
class boost::detail::quaternion_base
    : public boost::detail::binary_nion<T, 2>
{
    typedef binary_nion<T, 2> base_type;
    typedef quaternion_base<T> self_type;

public:
    // Template parameters
    typedef T value_type;

    // More information
    BOOST_STATIC_CONSTANT( std::size_t, component_count
     = base_type::component_count );

    typedef std::complex<T> complex_type;

    // Constructors (use automatic destructor and copy constructor)
    quaternion_base( value_type const &r0 = T(), value_type const &r1 = T(),
     value_type const &r2 = T(), value_type const &r3 = T() );

    quaternion_base( complex_type const &z0,
     complex_type const &z1 = complex_type() );

    #ifndef BOOST_NO_MEMBER_TEMPLATES
    template < typename U >
    quaternion_base( quaternion_base<U> const &copied );
    #endif

    // Operations
    void swap( self_type &b );

    // Components
    value_type R_component_1() const;
    value_type R_component_2() const;
    value_type R_component_3() const;
    value_type R_component_4() const;

    complex_type C_component_1() const;
    complex_type C_component_2() const;

    // Operators (use automatic regular assignment)
    bool operator ==( self_type const &other ) const;

    self_type & operator +=( self_type const &other );
    self_type & operator -=( self_type const &other );
    self_type & operator *=( self_type const &other );
    self_type & operator /=( self_type const &other );

    // Real and unreal
    value_type real() const;
    self_type unreal() const;

protected:
    quaternion_base( base_type const &copied );

};
//=========================================================================

Since addition and subtraction are done element-wise, I'll probably move the
definitions of operator+= and operator-= to binary_nion. I would do the
same for operator*= and operator/=, but I can't figure out the general rule.
Could you send it to me?

Now the main class, and its specializations can be written trivially:

//=========================================================================
template < typename T >
class boost::quaternion
    : public boost::detail::quaternion_base<T>
{
    typedef boost::detail::quaternion_base<T> base_type;
    typedef boost::quaternion<T> self_type;

public:
    // Types
    typedef T value_type;
    typedef std::complex<T> complex_type;

    // More information
    BOOST_STATIC_CONSTANT( std::size_t, component_count =
base_type::component_count );

    // Constructors (use automatic destructor and copy constructor)
    quaternion( value_type const &r0 = value_type(),
     value_type const &r1 = value_type(), value_type const &r2 =
value_type(),
     value_type const &r3 = value_type() )
        : base_type( r0, r1, r2, r3 )
    {
    }

    quaternion( complex_type const &z0, complex_type const &z1 =
complex_type() )
        : base_type( z0, z1 )
    {
    }

    #ifndef BOOST_NO_MEMBER_TEMPLATES
    template < typename U >
    quaternion( quaternion<U> const &copied )
        : base_type( static_cast<quaternion_base<U> const &>(copied) )
    {
    }
    #endif

    // The float, double, and long double specializations
    // would put their constructors to each other here.

    // Operations
    void swap( self_type &b )
        { this->base_type::swap( static_cast<base_type &>(b) ); }

    // Components
    value_type R_component_1() const { return
this->base_type::R_component_1(); }
    value_type R_component_2() const { return
this->base_type::R_component_2(); }
    value_type R_component_3() const { return
this->base_type::R_component_3(); }
    value_type R_component_4() const { return
this->base_type::R_component_4(); }

    complex_type C_component_1() const { return
this->base_type::C_component_1(); }
    complex_type C_component_2() const { return
this->base_type::C_component_2(); }

    // Operators (use automatic regular assignment)
    bool operator ==( self_type const &other ) const
    {
        return this->base_type::operator ==( static_cast<base_type const
&>(other) );
    }

    self_type & operator +=( self_type const &other )
    {
        this->base_type::operator +=( static_cast<base_type const &>(other)
);
        return *this;
    }
    self_type & operator -=( self_type const &other )
    {
        this->base_type::operator -=( static_cast<base_type const &>(other)
);
        return *this;
    }
    self_type & operator *=( self_type const &other )
    {
        this->base_type::operator *=( static_cast<base_type const &>(other)
);
        return *this;
    }
    self_type & operator /=( self_type const &other )
    {
        this->base_type::operator /=( static_cast<base_type const &>(other)
);
        return *this;
    }

    self_type & operator =( value_type const &other )
        { return this->operator =( self_type(other) ); }
    bool operator ==( value_type const &other ) const
        { return this->operator ==( self_type(other) ); }
    self_type & operator +=( value_type const &other )
        { return this->operator +=( self_type(other) ); }
    self_type & operator -=( value_type const &other )
        { return this->operator -=( self_type(other) ); }
    self_type & operator *=( value_type const &other )
        { return this->operator *=( self_type(other) ); }
    self_type & operator /=( value_type const &other )
        { return this->operator /=( self_type(other) ); }

    self_type & operator =( complex_type const &other )
        { return this->operator =( self_type(other) ); }
    bool operator ==( complex_type const &other ) const
        { return this->operator ==( self_type(other) ); }
    self_type & operator +=( complex_type const &other )
        { return this->operator +=( self_type(other) ); }
    self_type & operator -=( complex_type const &other )
        { return this->operator -=( self_type(other) ); }
    self_type & operator *=( complex_type const &other )
        { return this->operator *=( self_type(other) ); }
    self_type & operator /=( complex_type const &other )
        { return this->operator /=( self_type(other) ); }

    #ifndef BOOST_NO_MEMBER_TEMPLATES
    template < typename U >
    self_type & operator =( quaternion<U> const &other )
        { return this->operator =( self_type(other) ); }

    template < typename U >
    bool operator ==( quaternion<U> const &other ) const
        { return this->operator ==( self_type(other) ); }

    template < typename U >
    self_type & operator +=( quaternion<U> const &other )
        { return this->operator +=( self_type(other) ); }

    template < typename U >
    self_type & operator -=( quaternion<U> const &other )
        { return this->operator -=( self_type(other) ); }

    template < typename U >
    self_type & operator *=( quaternion<U> const &other )
        { return this->operator *=( self_type(other) ); }

    template < typename U >
    self_type & operator /=( quaternion<U> const &other )
        { return this->operator /=( self_type(other) ); }
    #endif

    // Real and unreal
    value_type real() const { return this->base_type::real(); }
    self_type unreal() const { return this->base_type::unreal(); }

protected:
    quaternion( base_type const &copied ) : base_type( copied ) {}

};

//...

boost::quaternion<float>::quaternion( quaternion<double> const &copied )
    : base_type( static_cast<detail::quaternion_base<double> const
&>(copied) )
{
}
    
boost::quaternion<float>::quaternion( quaternion<long double> const &copied
)
    : base_type( static_cast<detail::quaternion_base<long double> const
&>(copied) )
{
}
    
boost::quaternion<double>::quaternion( quaternion<float> const &copied )
    : base_type( static_cast<detail::quaternion_base<float> const &>(copied)
)
{
}
    
boost::quaternion<double>::quaternion( quaternion<long double> const &copied
)
    : base_type( static_cast<detail::quaternion_base<long double> const
&>(copied) )
{
}
    
boost::quaternion<long double>::quaternion( quaternion<float> const &copied
)
    : base_type( static_cast<detail::quaternion_base<float> const &>(copied)
)
{
}
    
boost::quaternion<long double>::quaternion( quaternion<double> const &copied
)
    : base_type( static_cast<detail::quaternion_base<double> const
&>(copied) )
{
}
//=========================================================================

There's more that can be done....

-- 
Daryle Walker
Mac, Internet, and Video Game Junkie
darylew AT mac DOT com

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk