2
votes

How can a template class instance receive another instance of the same template class of different type as an argument to some of its function member? (It's hard for me to express my question in simpler way and I'm so sorry for that.)

Here is a working code. I created a class and I named it MyClass. It accepts same template class of the same type(which is int) on its operator= and operator+ member functions.

#include <iostream>
using namespace std;

template<class T>
class MyClass {
protected:
  T __val;
public:
  MyClass();
  MyClass(T val): __val(val) {}
  void operator= (const MyClass<T>& r)
  {
    __val = (T)r.__val;
  }
  const MyClass<T>& operator+ (const MyClass<T>& r)
  {
    return *(new MyClass<T>(__val + (T)r.__val));
  }
  T retval() {return __val;}
};

int main()
{
  MyClass<int> myclass1(1);
  MyClass<int> myclass2(2);
  MyClass<int> myclass3 = myclass1 + myclass2;
  cout << myclass3.retval() << endl;
  return 0;
}

I typecasted __val members of arguments for operator= and operator+ for the following purpose:

int main()
{
  MyClass<int> myclass1(1);
  MyClass<double> myclass2(2.5);
  MyClass<int> myclass3 = myclass1 + myclass2;
  cout << myclass3.retval() << endl;
  return 0;
}

obviously I'll get an error. I cannot pass myclass2 as an argument to operator+ of myclass1 simply because MyClass<int>::operator+ wants MyClass<int> argument, and not MyClass<double>. I know that I can overload another operator+ that accepts MyClass<double>, but I also want to do it with other number types such as float, single, etc. Making overloaded functions for all of them makes my code bigger, which I obviously don't want to happen.

What do I have to change from MyClass to make my second main function work?

3
return *(new -- NONONONONONONDONTWHYNOSTOP.Xeo
Also, __names like that are reserved for the implementation, don't use them.Xeo
Another chapter of the Java++ reference manualManu343726

3 Answers

2
votes

You need a template member operator+. Also, it should return a value, not a reference:

template<class T>
class MyClass 
{
 public:
  template <typename T2>
  MyClass operator+ (const MyClass<T2>& r) const { return _val + r.retval(); }

  T retval() const {return _val;}

  // as before
};

Note that this will return a value of the same type as the LHS in an expression involving operator+. Note that it would be a better idea to implement operator+ as a non-member binary operator. But you have to implement some compile-time logic to determine the return type:

template <typename T1, typename T2>
MyClass< ?? > operator+(const MyClass<T1>& lhs, const MyClass<T1>& rhs)
{
  return lhs.retval() + rhs.retval();
}

where ?? should be replaced by a compile construct to pick a type based on T1 and T2. Presumably this would be one of those two types. This is a C++11 example:

template <typename T1, typename T2>
auto operator+(const MyClass<T1>& lhs, const MyClass<T1>& rhs)->decltype(lhs.retval()+rhs.retval())
{
  return lhs.retval() + rhs.retval();
}

This has the advantage that the return type is determined independent of what is on the LHS or RHS.

0
votes

You can write like:

template<typename _Ty> MyClass<T> operator+ (const MyClass<_Ty>& r) {
   return MyClass<T>(__val + (static_cast<_Ty> (r.__val)) );
}

to provide a member function. But to more generally support it do like:

template<typename _T,typename _Ty> MyClass<_T> operator+ (const Myclass<_T>& p,const MyClass<_Ty>& r) {
       return MyClass<T>(p.__val + (static_cast<_T> (r.__val)) );
    }

Unfortunately for that you have to declear __val as public

0
votes

Casting has stronger precendence than the dot, i.e. instead of

(T)r.__val

you have to write

(T) (r.__val)

Better, use static_cast. Hence, define operator + like

template<class S>
MyClass<T> operator+ (const MyClass<S>& r) {
   return MyClass<T>(__val + (static_cast<S> (r.__val)) );
}

Or don't use explicit casting at all:

template<class S>
MyClass<T> operator+ (const MyClass<S>& r) {
   return MyClass<T>(__val + r.__val);
}

It would be probably better to make retval return a const T &, use retval () in the implementation of operator +, and make operator + a non-member non-friend:

template<class T>
class MyClass {
private:
  T m_val;
public:
  MyClass(T val): m_val(val) {}
  const T & retval () const {return m_val;}
};

template<class T1, class T2>
auto operator+ (const MyClass<T1>& r1, const MyClass<T2> & r2)
-> MyClass < std::remove_const < std::remove_reference <
   decltype ( r1.retval () + r2.retval () ) 
> > > {
    return r1.retval () + r2.retval ();
}