$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
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