Update: clarification, more clear focus and shortened example:
- Can I circumvent the
M op+(M&&,M&&)overload? Assuming, I want good handling of RValues? I guess the other three overloads are required.
Reason why I have the (&&,&&) overload in the first place:
- Normally I would not provide
M op+(&&,&&), but I seem to need it: When providing overloads for(&&,&)and(&,&&)the compiler gets into an ambiguity. Is there a better way to resolve it then to add another implementation variant?
You can also look at the complete code.
struct Matrix {
...
// 2ary ops
friend Matrix operator+(const Matrix &a, Matrix &&b ) { b+=a; return move(b); }
friend Matrix operator+(Matrix &&a, const Matrix &b) { a+=b; return move(a); }
friend Matrix operator+(const Matrix &a, Matrix v) { v+=a; return v; }
friend Matrix operator+(Matrix &&a, Matrix &&b) { a+=b; return move(a); }
// ... same for operator*
// ... assume impl of operator+=,*= and move semantics
};
int main() {
Matrix a{2},b{3},c{4},d{5};
Matrix x = a*b + c*d; // reuires &&,&& overload
std::cout << x << std::endl;
}
The following helper function returns the first value if it an rvalue, otherwise the second value (which may be an rvalue, but may not be).
The following helper function returns the other value not returned above.
This just compares if two types are the same, ignoring references and const.
Then we can do just one overload for each function (using templates) like the following:
Note above, if either
M1orM2is an rvalue,get_rvalue(a, b)will return an rvalue, hence in this caseMatrix xwill be populated by a move, not a copy. Named return value optimisation will probably ensure that there is no copy (or even move) required into the return value, asxwill be constructed in the place of the return value.Full code is here.