overloading operators for template classes

Hello! Say I have a class like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template <typename T>
class myClass {
public:
 T x, y;
 myClass(T a, T b) {
  x = a;
  y = b;
 }
 const myClass operator+(const myClass &other) {
  myClass copy = *this;
  copy.x += other.x;
  copy.y += other.y;
  return copy;
 }
};


This works fine if I'm adding using the same template type, e.g.

1
2
myClass<float> a(1, 1), b(2, 2);
std::cout << (a + b).x << std::endl;


However, if I try it using two different template types, e.g.

1
2
3
myClass<float> a(1, 1);
myClass<double> b(2, 2);
std::cout << (a + b).x << std::endl;


The code won't compile. I'm wondering what's wrong w/ my class here, and how I can edit it so that the code in my previous example is possible.
The code won't compile.

What is the exact error message when you try to compile the second snippet?

And what exactly are you trying to accomplish?

What is the output of the first snippet?

What do you think would happen if you used a std::string for a or b?

The thing to note here is that myClass is not a class. It's a template. This means that it is used to create other classes.

Therefore... myClass<int> and myClass<float> are two distinctly different classes.

Your + operator only allows you to add one object of the class to another object of the same class. Therefore your 2nd example is failing because you have two different classes and are trying to add them together.


What you can do.. is you can template the + operator so it can take several different classes:

1
2
3
4
5
6
7
8
9
10
template <typename T>
class myClass
{

//...
     template <typename U>
     const myClass<T> operator + (const myClass<U>& other)
     {
         //...
     }


But this raises another problem. If you add a myClass<float> and a myClass<double>... what is the result? Is it a myClass<float> or a myClass<double>?

What if you add a myClass<float> and a myClass<string>?



EDIT:

Also, your + operator is ill formed. It's behaving like the += operator in that it is modifying the left-hand object. The + operator should be const and should not modify either object involved in the addition. Instead it should return the sum in a separate object.
Last edited on
What is the exact error message when you try to compile the second snippet?



error: no match for 'operator+' (operand types are myClass<double> and myClass<float>)


And what exactly are you trying to accomplish?


The class should have the ability to store x and y variables of any type, and the + operator should return an object of myClass where the x and y values of each operand are added.

What is the output of the first snippet?


3


What do you think would happen if you used a std::string for a or b?


Add them, so long as adding them was possible, otherwise (e.g. float + std::string) it should result in a compilation error (I think).
Last edited on
The thing to note here is that myClass is not a class. It's a template. This means that it is used to create other classes.

Therefore... myClass<int> and myClass<float> are two distinctly different classes.

Your + operator only allows you to add one object of the class to another object of the same class. Therefore your 2nd example is failing because you have two different classes and are trying to add them together.


ahhh ...I see. I didn't realize that templates worked this way at all. Thanks.

But this raises another problem. If you add a myClass<float> and a myClass<double>... what is the result? Is it a myClass<float> or a myClass<double>?

What if you add a myClass<float> and a myClass<string>?


I hadn't thought about that, I had just assumed that it would be a myClass<float>, since that was the type of the left hand. As for the std::string portion, refer to my previous post for what the expectation was there.

Also, your + operator is ill formed. It's behaving like the += operator in that it is modifying the left-hand object. The + operator should be const and should not modify either object involved in the addition. Instead it should return the sum in a separate object.


Take another look, I create a myClass object with the same values as this, and add the right hand's x and y values to that copy's x and y values, then return the copy. Neither side is being edited in any way, as far as I understand.
Add them, so long as adding them was possible, otherwise (e.g. float + std::string) it should result in a compilation error (I think).


That's correct. A compile error, just like you're now getting.

Yes, but I wouldn't think that would happen for types that can be added legitimately. What I mean is that you can do this:

1
2
3
float a = 5;
double b = 7;
float c = a + b;


but not this:

1
2
3
float a = 5;
std::string b = "Hello!";
float c = a + b;


And my expectation was that the template class's operator+ would produce a compilation error in cases where that would normally occur with the bare types. Obviously this isn't the case, but that's the nature of my question - WHY isn't it the case, and what steps would I take to induce that functionality (if any)?

EDIT:
In any case, Disch's answer did solve my problem (for the most part), so I'll mark this thread as solved now.
Last edited on
Take another look, I create a myClass object with the same values as this, and add the right hand's x and y values to that copy's x and y values, then return the copy. Neither side is being edited in any way, as far as I understand.


Whoops! You're right. I was mistaken. Sorry. =)
If you sum a float and a double the result would be a double
So you may want a similar behaviour: Class<float> + Class<double> -> Class<double>

You can do that in c++11, with decltype
1
2
3
4
5
6
7
8
9
//as a member function
template<class U>
auto operator+(const myClass<U> &b) const -> myClass<decltype(this->x + b.x)>{
	myClass<decltype(this->x + b.x)> result;
	result.x = this->x + b.x;
	result.y = this->y + b.y;

	return result;
}
¿is there a way to simplify the declaration of result?


Edit: of course, you could also do it as a non-member function
1
2
template<class T, class U>
auto operator+(const myClass <T> &a,  const amyClass<U> &b) -> myClass<decltype(a.x + b.x)>
Last edited on
Wow, I'd never seen decltype (even if I had I probably wouldn't have thought to use it like that). Thanks for showing me a great use for this feature!

¿is there a way to simplify the declaration of result?


¿You're asking me? Well I guess you let the template type resolve itself using the ctor...
1
2
3
4
5
template<class U>
auto operator+(const myClass<U> &b) const -> myClass<decltype(x + b.x)>{
 myClass result(x + b.x, y + b.y);
 return result;
}
Topic archived. No new replies allowed.