Boost logo

Boost :

From: Daniel Frey (daniel.frey_at_[hidden])
Date: 2002-03-22 05:17:06


Mark Rodgers wrote:
>
> From: "Aleksey Gurtovoy" <agurtovoy_at_[hidden]>
> > Here's a version of 'operators<>' template that allows "lazy"
> instantiation
> > of complementing operators:
>
> What about operations on different types - Duration + Date = Date, etc?

I tried to merge Alexsey's code with some older code of mine. A first
version shows that you can combine them, but there are some problems
with the granularity (I mean, to specify which of the 'friends' should
be used. The code I have is this:

// Play around with operators and their most generic definitions...

namespace boost
{
   template< typename Self > class operators
   {
   private:
      Self& self() { return static_cast< Self& >( *this ); }
      const Self& self() const { return static_cast< const Self& >(
*this ); }

   protected:
      inline bool operator!=( const Self& rhs ) const
      {
         return !( self() == rhs ); // x != y => !( x == y )
      }
      
      template< typename T >
      inline bool operator!=( const T& rhs ) const
      {
         return !( self() == rhs ); // x != y => !( x == y )
      }
      
      template< typename T >
      friend inline bool operator!=( const T& lhs, const Self& rhs )
      {
         return !( lhs == rhs ); // x != y => !( x == y )
      }
      
      //-------------------------------------------------------
      
      inline bool operator>( const Self& rhs ) const
      {
         return rhs < self(); // x > y => y < x
      }

      template< typename T >
      inline bool operator>( const T& rhs ) const
      {
         return rhs < self(); // x > y => y < x
      }

      template< typename T >
      friend inline bool operator>( const T& lhs, const Self& rhs )
      {
         return rhs < lhs; // x > y => y < x
      }
      
      //-------------------------------------------------------
      
      inline bool operator<=( const Self& rhs ) const
      {
         return !( self() > rhs ); // x <= y => !( x > y )
      }
      
      template< typename T >
      inline bool operator<=( const T& rhs ) const
      {
         return !( self() > rhs ); // x <= y => !( x > y )
      }
      
      template< typename T >
      friend inline bool operator<=( const T& lhs, const Self& rhs )
      {
         return !( lhs > rhs ); // x <= y => !( x > y )
      }
      
      //-------------------------------------------------------
      
      inline bool operator>=( const Self& rhs ) const
      {
         return !( self() < rhs ); // x >= y => !( x < y )
      }

      // gcc 2.95.2 seems to have a strange bug which forces me
      // to make this single operator public. Shouldn't be neccessary
      // for other compilers :)
   public:
      template< typename T >
      inline bool operator>=( const T& rhs ) const
      {
         return !( self() < rhs ); // x >= y => !( x < y )
      }
   protected:
      
      template< typename T >
      friend inline bool operator>=( const T& lhs, const Self& rhs )
      {
         return !( lhs < rhs ); // x >= y => !( x < y )
      }
      
      //-------------------------------------------------------

      template< typename T > inline Self& operator-=( const T& rhs )
      {
         return self() += -rhs; // x - y => x + -y
      }

      //-------------------------------------------------------
      
      friend inline Self operator+( const Self& lhs, const Self& rhs )
      {
         return Self( lhs ) += rhs;
      }

      template< typename T >
      friend inline Self operator+( const Self& lhs, const T& rhs )
      {
         return Self( lhs ) += rhs;
      }

      template< typename T >
      friend inline Self operator+( const T& lhs, const Self& rhs )
      {
         // Two alternatives are available
         
         return Self( rhs ) += lhs; // x + y => y + x
         
         // return Self( lhs ) += rhs;
         // uses conversion-ctor: Self( const T& ), potentially
dangerous
      }

      //-------------------------------------------------------
      
      friend inline Self operator-( const Self& lhs, const Self& rhs )
      {
         return Self( lhs ) -= rhs;
      }

      template< typename T >
      friend inline Self operator-( const Self& lhs, const T& rhs )
      {
         return Self( lhs ) -= rhs;
      }

      template< typename T >
      friend inline Self operator-( const T& lhs, const Self& rhs )
      {
         // Two alternatives are available
         
         return ( -Self( rhs ) ) += lhs; // x - y => -y + x
         
         // return Self( lhs ) -= rhs;
         // uses conversion-ctor: Self( const T& ), potentially
dangerous
      }

      //-------------------------------------------------------
      
      friend inline Self operator*( const Self& lhs, const Self& rhs )
      {
         return Self( lhs ) *= rhs;
      }

      template< typename T > friend inline Self operator*( const Self&
lhs, const T& rhs )
      {
         return Self( lhs ) *= rhs;
      }

      template< typename T > friend inline Self operator*( const T& lhs,
const Self& rhs )
      {
         // Two alternatives are available
         
         return Self( rhs ) *= lhs; // x * y => y * x
         // return Self( lhs ) *= rhs; // uses conversion-ctor: Self(
const T& ), potentially dangerous
      }

      //-------------------------------------------------------

      friend inline Self operator/( const Self& lhs, const Self& rhs )
      {
         return Self( lhs ) /= rhs;
      }

      template< typename T >
      friend inline Self operator/( const Self& lhs, const T& rhs )
      {
         return Self( lhs ) /= rhs;
      }

      template< typename T >
      friend inline Self operator/( const T& lhs, const Self& rhs )
      {
         return Self( lhs ) /= rhs;
         // uses conversion-ctor: Self( const T& ), potentially
dangerous
      }
   };
}

namespace X
{
   class A : public boost::operators< A >
   {
   private:
      typedef boost::operators< A > ops;
      
      int i_;

   public:
      explicit A( const int i ) : i_( i ) {}

      A( const A& rhs ) : i_( rhs.i_ ) {}
      ~A() {}

      operator int() const
      {
         return i_;
      }

      //-------------------------------------------------------
      // Special (logical)

      // The basics
      bool operator==( const A& rhs ) const { return i_ == rhs.i_; }
      bool operator<( const A& rhs ) const { return i_ < rhs.i_; }
      
      // Make 'A' work nicely with 'int'
      bool operator==( const int rhs ) const { return i_ == rhs; }
      bool operator<( const int rhs ) const { return i_ < rhs; }

      // Can this be done in a more generic way?
      // Self( lhs ) < rhs could be inefficient...
      friend bool operator<( const int lhs, const A& rhs )
      {
         return lhs < rhs.i_;
      }
      
      //-------------------------------------------------------
      // Special (arithmetic)

      // The basics
      inline A operator-() const { return A( -i_ ); }
      inline A& operator+=( const A& rhs ) { i_ += rhs.i_; return
*this; }
      inline A& operator*=( const A& rhs ) { i_ *= rhs.i_; return
*this; }
      inline A& operator/=( const A& rhs ) { i_ /= rhs.i_; return
*this; }

      // Make 'A' work nicely with 'int'
      inline A& operator+=( const int rhs ) { i_ += rhs; return
*this; }
      inline A& operator*=( const int rhs ) { i_ *= rhs; return
*this; }
      inline A& operator/=( const int rhs ) { i_ /= rhs; return
*this; }
      
      //-------------------------------------------------------
      // Generic (logical)

      // Same problem as for ++/--
      template< typename T >
      friend inline bool operator==( const T& lhs, const A& rhs )
      {
         // Two alternatives are available
         
         return rhs == lhs; // x == y => y == x
         
         // return A( lhs ) == rhs;
         // uses conversion-ctor: A( const T& ), potentially
dangerous
      }

      //-------------------------------------------------------

      using ops::operator!=;
      using ops::operator>;
      using ops::operator<=;
      using ops::operator>=;
      
      //-------------------------------------------------------
      // Generic (arithmetic)

      using ops::operator-=;

      // using ops::operator+;
      // using ops::operator-;
      // using ops::operator*;
      // using ops::operator/;
   };
}

//----------------------------------------------------------

#include <iostream>
using namespace std;

int main()
{
   int i = 1;
   X::A a( 1 );
   
   ( i += 2 ) += 3;
   ( a += 2 ) += 3;
   
   cout << i << " " << a << endl
        << ( i + 2 ) << " " << ( a + 2 ) << endl
        << ( 3 + i ) << " " << ( 3 + a ) << endl
        << ( i + i ) << " " << ( a + a ) << endl;

   cout << i << " " << a << endl
        << ( i - 2 ) << " " << ( a - 2 ) << endl
        << ( 3 - i ) << " " << ( 3 - a ) << endl
        << ( i - i ) << " " << ( a - a ) << endl;

   cout << i << " " << a << endl
        << ( i * 2 ) << " " << ( a * 2 ) << endl
        << ( 3 * i ) << " " << ( 3 * a ) << endl
        << ( i * i ) << " " << ( a * a ) << endl;

   cout << i << " " << a << endl
        << ( i / 2 ) << " " << ( a / 2 ) << endl
        << ( 3 / i ) << " " << ( 3 / a ) << endl
        << ( i / i ) << " " << ( a / a ) << endl;

   cout << ( i == 2 ) << " " << ( a == 2 ) << endl
        << ( 2 == i ) << " " << ( 2 == a ) << endl
        << ( i == i ) << " " << ( a == a ) << endl;
   
   cout << ( i >= 2 ) << " " << ( a >= 2 ) << endl
        << ( 2 >= i ) << " " << ( 2 >= a ) << endl
        << ( i >= i ) << " " << ( a >= a ) << endl;

   return 0;
}

Regards, Daniel

--
Daniel Frey
aixigo AG - financial training, research and technology
Schloß-Rahe-Straße 15, 52072 Aachen, Germany
fon: +49 (0)241 936737-42, fax: +49 (0)241 936737-99
eMail: daniel.frey_at_[hidden], web: http://www.aixigo.de

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