Reputation: 1577
I want to implement a kind of "number-like" mathematical objects (say, elements in a group or a ring) in C++. I'm sure that I'm not the only one dealing with this problem, so there may be abundant amount of discussions about what is the "best" way of overloading arithmetic operators. However, I couldn't find satisfactory answers (although maybe I was too lazy to googling more).
Let's say I want to overload the operator "+" for a class A. The problem is, there are too many different overloads I can think of:
First question. Do all of these overloads necessary to make operations on instances of A as efficient as, and as much as "being like primitive types" as possible? I think for "ordinary" cases, rvalue-qualified A::operator+= need not (or should not) be overloaded. Is it right? I think all of 1-4 are necessary. For example, for the case 3, since x is being moved, we do not need to allocate a new space to hold the return value, and we can safely reuse the allocation storage reserved for x. Is it right?
Second question. I think all of these overloads may share a lot of codes for most of this kind of cases. How can I minimize the code duplication without sacrificing performance/etc.? Is there any special techniques/idioms to do this? I prefer general and extensible methods, if exist.
Upvotes: 6
Views: 4998
Reputation: 141586
It's not possible to give a most-general answer, because choosing the "best" way will involve an appreciation of details about the operation.
For example the most common pattern (which I give below) is not so good for Matrix Multiplication, because in that case it is simplest to declare a third matrix that starts off zeroed and reads the two arguments. Also you may want to use lazy evaluation in which case none of this applies.
I would recommend making sure that your code gives the correct answers for all cases, and you can worry about micro-optimization later once your program works and once you have more experience in the language.
For a class where the most efficient way to implement +
is to modify one of the arguments, then the following two cases cover all uses, with the strong exception guarantee:
A& A::operator+=(A const &y) { /* modify *this using y */ ; return *this; }
A operator+ ( A x, A const& y ) { x += y; return x; }
For more explanation about what the above code does and why, see the operator overloading megathread.
In C++03 it didn't make much difference to use A const& x
instead of A x
, but in C++11 this is slightly more optimal for the case where the first argument is an rvalue, because resources can now be stolen from the first argument.
Regarding the decision to use ref-qualifiers on operator+=
. There is no benefit to overloading separate for &
and &&
. If you have seen people using &
, the rationale is not to also overload, but to give a compile error for the attempt to use +=
on an rvalue; with the rationale being that that's likely to be a mistake.
Upvotes: 5