Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

operator overloading with multiple templates

template <class T>
class A
{
    private:
        T m_var;
    public:
        operator T () const { return m_var; }
        ........
}

template<class T, class U, class V>
const A<T> operator+ (const U& r_var1, const V& r_var2)
{ return A<T> ( (T)r_var1 + (T)r_var2 ); }

The idea is to overload the + operator once (instead of three) for the cases: number + A, A + number, A + A (where number is of type T, the same as m_var). An interesting case would be if m_var is e.g. int and r_var is long.

Any helps would be highly appreciated. Thank you.

like image 398
meta-cpp Avatar asked Jan 21 '23 15:01

meta-cpp


2 Answers

The common pattern to achieve what you want is to actually perform it in the opposite direction: provide an implicit conversion from T to the template and only define the operator for the template.

template <typename T>
struct test {
   T m_var;
   test( T const & t ) : m_var(t) {}   // implicit conversion
   test& operator+=( T const & rhs ) {
      m_var += rhs.m_var;
   }
   friend test operator+( test lhs, test const & rhs ) { // *
      return lhs += rhs;
   }
};
// * friend only to allow us to define it inside the class declaration

A couple of details on the idiom: operator+ is declared as friend only to allow us to define a free function inside the class curly braces. This has some advantages when it comes to lookup for the compiler, as it will only consider that operator if either one of the arguments is already a test.

Since the constructor is implicit, a call test<int> a(0); test<int> b = a + 5; will be converted into the equivalent of test<int> b( a + test<int>(5) ); Conversely if you switch to 5 + a.

The operator+ is implemented in terms of operator+=, in a one-liner by taking the first argument by value. If the operator was any more complex this would have the advantage of providing both operators with a single implementation.

like image 184
David Rodríguez - dribeas Avatar answered Jan 27 '23 21:01

David Rodríguez - dribeas


The issue with your operator+ is you have 3 template parameters, one for the return type as well as the cast, but there is no way for the compiler to automatically resolve that parameter.

You are also committing a few evils there with casts.

You can take advantage of the that if you define operator+ as a free template function in your namespace it will only have effect for types defined in that namespace.

Within your namespace therefore I will define, using just T and U

template< typename T >
T operator+( const T & t1, const T& t2 )
{
   T t( t1 );
   t += t2; // defined within T in your namespace
   return t;
}

template< typename T, typename U >
T operator+( const T& t, const U& u )
{
    return t + T(u);
}

template< typename T, typename U >
T operator+( const U& u, const T& t )
{
   return T(u) + t;
}

a + b in general is not covered by this template unless one of the types of a and b is in the namespace where the template was defined.

like image 24
CashCow Avatar answered Jan 27 '23 22:01

CashCow