Overloading on R-value references and code duplication - c++

Consider the following:
struct vec
{
int v[3];
vec() : v() {};
vec(int x, int y, int z) : v{x,y,z} {};
vec(const vec& that) = default;
vec& operator=(const vec& that) = default;
~vec() = default;
vec& operator+=(const vec& that)
{
v[0] += that.v[0];
v[1] += that.v[1];
v[2] += that.v[2];
return *this;
}
};
vec operator+(const vec& lhs, const vec& rhs)
{
return vec(lhs.v[0] + rhs.v[0], lhs.v[1] + rhs.v[1], lhs.v[2] + rhs.v[2]);
}
vec&& operator+(vec&& lhs, const vec& rhs)
{
return move(lhs += rhs);
}
vec&& operator+(const vec& lhs, vec&& rhs)
{
return move(rhs += lhs);
}
vec&& operator+(vec&& lhs, vec&& rhs)
{
return move(lhs += rhs);
}
Thanks to r-value references, with these four overloads of operator+ I can minimize the number of objects created, by reusing temporaries. But I don't like the duplication of code this introduces. Can I achieve the same with less repetition?

Recycling temporaries is an interesting idea and you're not the only one who wrote functions that return rvalue references for this reason. In an older C++0x draft operator+(string&&,string const&) was also declared to return an rvalue reference. But this changed for good reasons. I see three issues with this kind of overloading and choice of return types. Two of them are independent of the actual type and the third argument refers to the kind of type that vec is.
Safety issues. Consider code like this:
vec a = ....;
vec b = ....;
vec c = ....;
auto&& x = a+b+c;
If your last operator returns an rvalue reference, x will be a dangling reference. Otherwise, it won't. This is not an artificial example. For example, the auto&& trick is used in the for-range loop internally to avoid unnecessary copies. But since the life-time extension rule for temporaries during reference binding does not apply in case of a function call that simply returns a reference, you'll get a dangling reference.
string source1();
string source2();
string source3();
....
int main() {
for ( char x : source1()+source2()+source3() ) {}
}
If the last operator+ returned an rvalue reference to the temporary that is created during the first concatenation, this code would invoke undefined behaviour because the string temporary would not exist long enough.
In generic code, functions that return rvalue references force you to write
typename std::decay<decltype(a+b+c)>::type
instead of
decltype(a+b+c)
simply because the last op+ might return an rvalue reference. This is getting ugly, in my humble opinion.
Since your type vec is both "flat" and small, these op+ overloads are hardly useful. See FredOverflow's answer.
Conclusion: Functions with an rvalue reference return type should be avoided especially if these references may refer to short-lived temporary objects. std::move and std::forward are special-purpose exceptions to this rule of thumb.

Since your vec type is "flat" (there is no external data), moving and copying do exactly the same thing. So all your rvalue references and std::moves gain you absoutely nothing in performance.
I would get rid of all additional overloads and just write the classic reference-to-const version:
vec operator+(const vec& lhs, const vec& rhs)
{
return vec(lhs.v[0] + rhs.v[0], lhs.v[1] + rhs.v[1], lhs.v[2] + rhs.v[2]);
}
In case you have little understanding of move semantics yet, I recommend studying this question.
Thanks to r-value references, with these four overloads of operator+ I can minimize the number of objects created, by reusing temporaries.
With a few exceptions, returning rvalue references is a very bad idea, because calls of such functions are xvalues instead of prvalues, and you can get nasty temporary object lifetime problems. Don't do it.

This, which already works wonderfully in current C++, will use move semantics (if available) in C++0x. It already handles all cases, but relies on copy elision and inlining to avoid copies – so it may make more copies than desired, particularly for the second parameter. The nice bit about this is it works without any other overloads and does the right thing (semantically):
vec operator+(vec a, vec const &b) {
a += b;
return a; // "a" is local, so this is implicitly "return std::move(a)",
// if move semantics are available for the type.
}
And this is where you would stop, 99% of the time. (I am likely underestimating that figure.) The rest of this answer only applies once you know, such as through the use of a profiler, that extra copies from op+ are worth further optimization.
To completely avoid all possible copies/moves, you would indeed need these overloads:
// lvalue + lvalue
vec operator+(vec const &a, vec const &b) {
vec x (a);
x += b;
return x;
}
// rvalue + lvalue
vec&& operator+(vec &&a, vec const &b) {
a += b;
return std::move(a);
}
// lvalue + rvalue
vec&& operator+(vec const &a, vec &&b) {
b += a;
return std::move(b);
}
// rvalue + rvalue, needed to disambiguate above two
vec&& operator+(vec &&a, vec &&b) {
a += b;
return std::move(a);
}
You were on the right track with yours, with no real reduction possible (AFAICT), though if you need this op+ often for many types, a macro or CRTP could generate it for you. The only real difference (my preference for separate statements above is minor) is yours make copies when you add two lvalues in operator+(const vec& lhs, vec&& rhs):
return std::move(rhs + lhs);
Reducing duplication through CRTP
template<class T>
struct Addable {
friend T operator+(T const &a, T const &b) {
T x (a);
x += b;
return x;
}
friend T&& operator+(T &&a, T const &b) {
a += b;
return std::move(a);
}
friend T&& operator+(T const &a, T &&b) {
b += a;
return std::move(b);
}
friend T&& operator+(T &&a, T &&b) {
a += b;
return std::move(a);
}
};
struct vec : Addable<vec> {
//...
vec& operator+=(vec const &x);
};
Now there's no longer a need to define any op+ specifically for vec. Addable is reusable for any type with op+=.

I coded up Fred Nurk's answer using clang + libc++. I had to remove the use of initializer syntax because clang doesn't yet implement that. I also put a print statement in the copy constructor so that we could count copies.
#include <iostream>
template<class T>
struct AddPlus {
friend T operator+(T a, T const &b) {
a += b;
return a;
}
friend T&& operator+(T &&a, T const &b) {
a += b;
return std::move(a);
}
friend T&& operator+(T const &a, T &&b) {
b += a;
return std::move(b);
}
friend T&& operator+(T &&a, T &&b) {
a += b;
return std::move(a);
}
};
struct vec
: public AddPlus<vec>
{
int v[3];
vec() : v() {};
vec(int x, int y, int z)
{
v[0] = x;
v[1] = y;
v[2] = z;
};
vec(const vec& that)
{
std::cout << "Copying\n";
v[0] = that.v[0];
v[1] = that.v[1];
v[2] = that.v[2];
}
vec& operator=(const vec& that) = default;
~vec() = default;
vec& operator+=(const vec& that)
{
v[0] += that.v[0];
v[1] += that.v[1];
v[2] += that.v[2];
return *this;
}
};
int main()
{
vec v1(1, 2, 3), v2(1, 2, 3), v3(1, 2, 3), v4(1, 2, 3);
vec v5 = v1 + v2 + v3 + v4;
}
test.cpp:66:22: error: use of overloaded operator '+' is ambiguous (with operand types 'vec' and 'vec')
vec v5 = v1 + v2 + v3 + v4;
~~~~~~~ ^ ~~
test.cpp:5:12: note: candidate function
friend T operator+(T a, T const &b) {
^
test.cpp:10:14: note: candidate function
friend T&& operator+(T &&a, T const &b) {
^
1 error generated.
I fixed this error like so:
template<class T>
struct AddPlus {
friend T operator+(const T& a, T const &b) {
T x(a);
x += b;
return x;
}
friend T&& operator+(T &&a, T const &b) {
a += b;
return std::move(a);
}
friend T&& operator+(T const &a, T &&b) {
b += a;
return std::move(b);
}
friend T&& operator+(T &&a, T &&b) {
a += b;
return std::move(a);
}
};
Running the example outputs:
Copying
Copying
Next I tried a C++03 approach:
#include <iostream>
struct vec
{
int v[3];
vec() : v() {};
vec(int x, int y, int z)
{
v[0] = x;
v[1] = y;
v[2] = z;
};
vec(const vec& that)
{
std::cout << "Copying\n";
v[0] = that.v[0];
v[1] = that.v[1];
v[2] = that.v[2];
}
vec& operator=(const vec& that) = default;
~vec() = default;
vec& operator+=(const vec& that)
{
v[0] += that.v[0];
v[1] += that.v[1];
v[2] += that.v[2];
return *this;
}
};
vec operator+(const vec& lhs, const vec& rhs)
{
return vec(lhs.v[0] + rhs.v[0], lhs.v[1] + rhs.v[1], lhs.v[2] + rhs.v[2]);
}
int main()
{
vec v1(1, 2, 3), v2(1, 2, 3), v3(1, 2, 3), v4(1, 2, 3);
vec v5 = v1 + v2 + v3 + v4;
}
Running this program produced no output at all.
These are the results I got with clang++. Interpret them how you may. And your milage may vary.

Related

Problems building a SquareMatrix template class

I am trying to build a SquareMatrix template class by using a constructor that accepts 4 parameters as the 4 submatrices a, b, c, d occupying the four quadrants (a = northwest, b = northeast, c = southwest, d = southeast) of the matrix. Shown below:
template<class T> class SquareMatrix {
public:
SquareMatrix(){}
SquareMatrix(const T first, const T second, const T third, const T fourth) {
a = first;
b = second;
c = third;
d = fourth;
}
SquareMatrix<T>(const SquareMatrix<T>& rhs) { // copy constructor
a = rhs.getA();
b = rhs.getB();
c = rhs.getC();
d = rhs.getD();
}
SquareMatrix& operator=(const SquareMatrix rhs) { // assignment operator
if (&rhs != this) {
SquareMatrix(rhs);
}
return *this;
}
~SquareMatrix() {} // destructor
// getters and setters
T getA() const {return a;}
T getB() const {return b;}
T getC() const {return c;}
T getD() const {return d;}
void setA(const T& input) {a = input;}
void setB(const T& input) {b = input;}
void setC(const T& input) {c = input;}
void setD(const T& input) {d = input;}
private:
// 4 quadrants
// [a, b;
// c, d]
T a, b, c, d;
};
template<class T> SquareMatrix<T> operator+(const SquareMatrix<T> lhs,
const SquareMatrix<T>& rhs) {
SquareMatrix<T> ret(lhs);
ret.setA( ret.getA() + rhs.getA() );
ret.setB( ret.getB() + rhs.getB() );
ret.setC( ret.getC() + rhs.getC() );
ret.setD( ret.getD() + rhs.getD() );
return ret;
};
template<class T> SquareMatrix<T> operator-(const SquareMatrix<T> lhs,
const SquareMatrix<T>& rhs) {
SquareMatrix<T> ret(lhs);
ret.setA( ret.getA() - rhs.getA() );
ret.setB( ret.getB() - rhs.getB() );
ret.setC( ret.getC() - rhs.getC() );
ret.setD( ret.getD() - rhs.getD() );
return ret;
};
// this is the implementation of Strassen's algorithm
template<class T> SquareMatrix<T> operator*(const SquareMatrix<T>& lhs,
const SquareMatrix<T>& rhs) {
T product_1 = lhs.getA() * ( rhs.getB() - rhs.getD() );
T product_2 = ( lhs.getA() + lhs.getB() ) * rhs.getD();
T product_3 = ( lhs.getC() + lhs.getD() ) * rhs.getA();
T product_4 = lhs.getD() * ( rhs.getC() - rhs.getA() );
T product_5 = ( lhs.getA() + lhs.getD() ) * ( rhs.getA() + rhs.getD() );
T product_6 = ( lhs.getB() - lhs.getD() ) * ( rhs.getC() + rhs.getD() );
T product_7 = ( lhs.getA() - lhs.getC() ) * ( rhs.getA() + rhs.getB() );
SquareMatrix<T> ret;
ret.setA(product_5 + product_4 - product_2 + product_6);
ret.setB(product_1 + product_2);
ret.setC(product_3 + product_4);
ret.setD(product_1 + product_5 - product_3 - product_7);
return ret;
};
Now, I am trying to create a nested 4x4 matrix, by doing:
int main() {
cout << "Example: a 4x4 matrix: " << endl;
// 4 single quadrants
SquareMatrix<int> M_1A(1, 2, 3, 4);
SquareMatrix<int> M_1B(5, 6, 7, 8);
SquareMatrix<int> M_1C(9, 10, 11, 12);
SquareMatrix<int> M_1D(13, 14, 15, 16);
// 4x4 matrix M_1
SquareMatrix< SquareMatrix<int> > M_1(M_1A, M_1B, M_1C, M_1D);
// test
cout << "test: " << endl;
cout << M_1.getA().getA() << endl;
return 0;
}
The intended matrix output should be M_1 = [1,2,5,6; 3,4,7,8; 9,10,13,14; 11,12,15,16].
I use the M_1.getA().getA() command to first access M_1A and then access 1 nested inside it, but instead the output display a big number that constantly changes, perhaps an address? (last time I tried it yielded 6684672).
Is there a way to implement a matrix class in this manner?
(EDIT: now included assignment operator and destructor, likely sources of the bug)
As the comments suggested, it is the assignment operator that is faulty.
SquareMatrix& operator=(const SquareMatrix rhs) {
if (&rhs != this) {
SquareMatrix(rhs); // <-- This creates a temporary that
// dies off after that line is executed
}
return *this;
}
The assignment operator doesn't do any assignment. Instead a temporary SquareMatrix is made.
To fix this problem, either
1) Not supply any assignment operator, copy constructor, or destructor, since the type T should be safely copyable.
2) Fix the assignment operator so that it works correctly:
#include <algorithm>
//...
SquareMatrix& operator=(const SquareMatrix rhs) {
if (&rhs != this) {
SquareMatrix t(rhs);
std::swap(t.a, a);
std::swap(t.b, b);
std::swap(t.c, c);
std::swap(t.d, d);
}
return *this;
}
The assignment now works. However I suggest not writing code that need not be written, and your buggy implementation is the case in point.
In your case, if you let the compiler generate the assignment operator and/or rely on T in the template to have correct copy semantics, your class would have worked correctly.
Paul's comments are right on the mark. Although your SquareMatrix is not built-in, it is declared to be consisting of 4 elements of type T. The default copy c'tor for your class will be using the assignment operator or assignment c'tor of the actual type that T is representing in your usage.
I have some suggestions to improve the code:
If T is of a type that has a memory footprint that is bigger than a pointer/int: it is more efficient to let your c'tor receive the elements bij const reference like so:
SquareMatrix( const T& _a, const T& _b, const T& _c, const T& _d)
Use copy constructors as much as possible: that way the four elements don't get initialized first and then assigned later. Instead, they get initialized with the correct values at once.
SquareMatrix( const T& _a, const T& _b, const T& _c, const T& _d)
: a( _a), b( _b), c( _c), d( _d)
{ /* empty body */ }
Choose your names wisely to simplify things. Don't introduce extra mappings in name schemes when you don't have to; it just creates opportunities to slip. I already applied that in point 1 above :-).
Don't 'program by wishful thinking': writing in comments or type/variable names that something is supposed to be something will not make it that. In your case: your class IS NOT a square matrix, nor even a matrix. To the compiler it is a data type consisting of four elements, named a, b, c and d, respectively, of a type T to be defined at compile time.

R-values appear to provide incomplete support for unnamed temporaries, or am I missing something here?

R-values appear to provide incomplete support for unnamed temporaries, or am I missing something here?
C++11 provides excellent support for rvalues to implement move semantics, useful for converting expensive allocate and copy cycles into fast and cheap moves in constant time, similar to moving a reference. But C++11 came late in the game, and by then I had a fully developed solution to the costly unnamed temporaries problem, using the class-based solution outlined below.
Only when I recently attempted to replace my solution with with "modern" C++11 move constructors, did I discover rvalue management doesn't cover important cases that the class-based solution covers. A representative example is the expression A + B. When A is an unnamed temporary (rvalue), an in-place implementation of A += B is appropriate, when A is not an unnamed temporary (lvalue), A + B computes a new result. But C+11 rvalue support appears to address only a right argument rvalue, but not a left rvalue.
By extension, this limitation affect all other operators and functions on the base type that could benefit from treating *this as an rvalue when appropriate. Note that A + B can even be computed as B += A, when A is an lvalue and B is an rvalue. The benefits from a complete solution can often be applied more to *this rvalues than to right argument rvalues. If C++11 provides only a half solution here, then the class-based solution below remains significantly superior for many things. Am I missing something here?
So let's derive an unnamed temporary T class from the class of S values, add appropriate constructors, assignments, operators and functions to S and T, then substitute T for S as the return type for all functions and operators that return an S result. With this, we get all the same move semantics as with rvalues, plus support for additional functions and operators that can operate faster on unnamed temporary values in-place.
class S { // S is a sample base type to extend
protected:
mutable char* p; // mutable pointer to storage
mutable int length; // mutable current length
mutable int size; // mutable current size
public:
~S ( ); // S destructor
S (char* s); // construct from data
S (const S& s); // from another S
S (const T& s); // construct from an unnamed temporary
T& result ( ) { return (T&)*this; } // cast *this into a T& (an equivalent to std::move (*this))
S& take (S& s); // free *this, move s to *this, put s in empty/valid state
S& operator= (const S& s); // copy s to *this
S& operator= (const T& s); // assign from unnamed temporary using take ( )
S& operator+= (const S& v); // add v to *this in-place
S& operator-= (const S& v); // subtract v from *this in-place
S& operator<<= (Integer shift); // shift *this in-place
S& operator>>= (Integer shift);
T operator+ (const S& v); // add v to *this and return a T
T operator- (const S& v); // subtract v from *this and return a T
etc...
};
class T : public S { // T is an unnamed temporary S
private:
T& operator= (const T& s); // no public assignments
void* operator new (size_t size); // don't define -- no heap allocation
void operator delete (void* ptr);
public:
T (char* s) : S (s) { }; // create a new temporary from data
T (const S& s) : S (s) { }; // copy a new temporary from a non-temporary
T (const T& s) : S (s) { }; // move a temporary to new temporary
T operator<< (int shift) const { return ((S&)*this <<= shift).result ( ); }
T operator>> (int shift) const { return ((S&)*this >>= shift).result ( ); }
T operator+ (const S& v) const { return ((S&)*this += v).result ( ); }
T operator- (const S& v) const { return ((S&)*this -= v).result ( ); }
};
Note that this method has demonstrated its correctness and effectiveness across a variety of comprehensive data types (including strings, arrays, large integers, etc) since 2001, so it works without any reference to C++11 features, and relies on no undefined language features.
You appear to be wrong in your assumptions. C++ supports rvalues on either the left or the right.
There are two ways to do this.
struct noisy {
noisy() { std::cout << "ctor()\n"; };
noisy(noisy const&) { std::cout << "ctor(const&)\n"; };
noisy(noisy &&) { std::cout << "ctor(&&)\n"; };
noisy& operator=(noisy const&) { std::cout << "asgn(const&)\n"; return *this; };
noisy& operator=(noisy &&) { std::cout << "asgn(&&)\n"; return *this; };
~noisy() { std::cout << "dtor\n"; };
};
struct Bob:noisy {
int val = 0;
Bob(int x=0):val(x) {}
Bob(Bob&&)=default;
Bob(Bob const&)=default;
Bob& operator=(Bob&&)=default;
Bob& operator=(Bob const&)=default;
friend Bob operator+( Bob lhs, Bob const& rhs ) {
lhs += rhs;
return lhs;
}
friend Bob& operator+=( Bob& lhs, Bob const& rhs ) {
lhs.val += rhs.val;
return lhs;
}
friend Bob operator+=( Bob&& lhs, Bob const& rhs ) {
lhs += rhs; // uses & overload above
return std::move(lhs);
}
};
Bob uses friend operators to do basically what you want.
This is my preferred solution, friend operators are far more symmetric than member operators are.
struct Alice:noisy {
int val = 0;
Alice(int x=0):val(x) {}
Alice(Alice&&)=default;
Alice(Alice const&)=default;
Alice& operator=(Alice&&)=default;
Alice& operator=(Alice const&)=default;
Alice operator+( Alice const& rhs ) const& {
return Alice(*this) + rhs;
}
Alice operator+( Alice const& rhs ) && {
*this += rhs;
return std::move(*this);
}
Alice& operator+=( Alice const& rhs )& {
val += rhs.val;
return *this;
}
Alice operator+=( Alice const& rhs )&& {
*this += rhs; // uses & overload above
return std::move(*this);
}
};
Alice uses member functions to do the same. It has the usual problems with member functions over friend operators.
Notice the use of & and && and const& after the member function arguments. This is known as the "rvalue reference to *this" feature in casual discussion. It lets you pick which overload based on the r/l value-ness of the object being worked with.
Test code:
Bob bob;
Bob b2 = Bob{3}+bob;
Alice alice;
Alice a2 = Alice{3}+alice;
Live example.
In neither case, no objects are copied.
Note that I assumed addition was assymetric (despite using an int for state). If it was, you can do another efficiency where the lhs is a non-rvalue while the rhs is.

In C++, is there any way to reduce the number of member functions with move semantics?

I am trying to write my vec class. For efficiency, I use move semantics.
Vec<int> v1;
Vec<int> v2;
Vec<int> v3;
Vec<int> v4;
v4 = v1 + v2; // Line 1
v4 = v1 + v2 + v3; // Line 2
v4 = v1 + (v2 + v3); // Line 3
But, to let each line above only calls copy constructor once, I have to overload four function with one operator. Like the codes below.
Vec(Myself&& v)
{ // move consturctor
dim = v.dim;
value = std::move(v.value);
}
Myself& operator+= (const Myself& v)
{
for (size_type i = 0; i < dim; ++i) (*this)[i] += v[i];
return *this;
}
template<typename std::enable_if<!std::is_reference<Myself>::value>::type* = nullptr> // SFINAE
friend Myself& operator+ (Myself&& a, const Myself& b)
{
return a += b;
}
Myself& operator+ (Myself&& v) const
{
return v += *this;
}
Myself operator+ (const Myself& v) const
{
Myself ansV(*this);
ansV += v;
return ansV;
}
Thanks for Lightness Races in Orbit's reminder. I added the move constructor into the codes above.
1. Is there any way to write less functions for one operator?
2. Why the SFINAE is added at the function friend Myself& operator+ (Myself&& a, const Myself& b), not Myself& operator+ (Myself&& v) const? It is used to fixed the confusion of v4 = v1 + (v2 + v3);.
When I write operators for an arithmetic class T, I usually do the following:
(a) If the operation is commutative (a+b equals b+a):
Put the implementation of += into T:
T & T::operator+=(T const& other) {
// [Perform the actual operation (add other to *this)]
x += other.x; // or something similar
return *this;
}
Provide the following two functions outside the class:
T operator+(T a, T const& b) {
a += b;
return a;
}
T operator+(T const& a, T && b) {
MyInt temp(std::move(b));
temp += a;
return temp;
}
(b) If the operation is not commutative (a-b is different from b-a):
Put the implementation of -= into T and provide a second function that works on the second operand instead of the first:
T & T::operator-=(T const& other) {
// [Perform the actual operation of (subtract other from *this)]
x -= other.x; // or something similar
return *this;
}
void T::operatorMinus(T & other) const {
// [Perform the actual operation, but work on other instead of *this]
other.x = x - other.x; // or something similar
}
Provide the following two functions outside the class:
T operator-(T a, T const& b) {
a -= b;
return a;
}
T operator-(T const& a, T && b) {
MyInt temp(std::move(b));
a.operatorMinus(temp);
return temp;
}
Result:
Both gcc and clang now only need a single copy constructor in the following examples using -O3 (same for operator-):
T a1, a2, a3, x;
x = a1 + a2;
x = a1 + a2 + a3;
x = (a1 + a2) + a3;
x = a1 + (a2 + a3);
Even the case where both operands are rvalues is handled without ambiguity. The following compiles fine, even though two copies are needed (one copy for a1+a2 and one copy for a3+a4):
T a1, a2, a3, a4, x;
x = (a1 + a2) + (a3 + a4);

Error: initial value of reference to non-const must be an value

class A
{
public:
int v;
A * p;
A& operator*(const A& a)
{
return this->v*a.v// here is a red line under this say error initial value of reference to non-const must be an value
}
~A()
{
this;
}
};
int main()
{
A a;
a.p = new A;
delete a.p;
return 0;
system("pause");
return 0;
}
overloading * operator I cannot use this to represent the object itself. Why this happened.
Surely it says that it must be an lvalue. You're trying to return a reference to a temporary. This is bad karma.
Besides, it's not at all what you want. The multiplication operator should definitely return a value, not a reference.
Not sure what your constructor looks like, but assuming it takes an integer:
A operator * (A const& other) const
{
return A{ v * other.v};
};
Edit:
And actually you should go a step further:
struct A
{
A& operator *= (A const& other) { v *= other.v; return *this; }
A(int i) : v(i) {}
private:
int v;
}
A operator * (A lh, A const& rh)
{
A res{std::move(lh)};
res *= rh;
return res;
}
this->v*a.v evaluates to an int. An int cannot be converted to an A&.
Use
A operator*(const A& a) // Return a value, not a reference.
{
A res;
res.v = this->v*a.v;
return res;
}
You should make the member function a const member function too since it does not modify the object.
A operator*(const A& a) const
{
A res;
res.v = this->v*a.v;
return res;
}
The result of this->v * a.v is an rvalue, a temporary unnamed value. As a temporary, it cannot bind to a non-const reference. Only lvalues can bind to non-const references. That's what the error "initial value of reference to non-const must be an lvalue" is referring to.
However, you don't want to return a const reference either, you want to return the value by value:
A operator*(const A& a) { … }
^ remove &
Note: this will not fix your code completely as you're trying to return an int where you declared to return an A, and int isn't implicitly convertible to A in your current code.

Why can't I pass this class as a reference when returned from arithmetic operators?

If I have a simple class like this:
template<typename T>
class coord
{
public:
coord() : x(0), y(0)
{
}
coord(T X, T Y) : x(X), y(Y)
{
}
T x;
T y;
coord& operator-=(const coord& rhs)
{
(*this).x -= rhs.x;
(*this).y -= rhs.y;
return *this;
}
coord& operator+=(const coord& rhs)
{
(*this).x += rhs.x;
(*this).y += rhs.y;
return *this;
}
};
Along with the following operators (they're not friends because there's no private members to access).
template<typename T = int>
inline coord<T> operator-(coord<T> lhs, const coord<T>& rhs)
{
lhs -= rhs;
return lhs;
}
template<typename T = int>
inline coord<T> operator+(coord<T> lhs, const coord<T>& rhs)
{
lhs += rhs;
return lhs;
}
Elsewhere in my code I have another class A with a method that looks like this:
void A::SetVarC(coord<int>& c)
{
m_c = c;
}
(assume there's a getter for m_c as well)
When I try to invoke this method using the addition and subtraction operators I overloaded:
int x = 1;
int y = 1;
A* a = new A();
coord c1(1,2);
a->SetVarC(c1 - a->GetVarC() + coord<int>(x,y));
I get an error that there's no known conversion from coord<int> to coord<int>&. I can see that my subtraction and addition operators aren't returning references, but I thought that wouldn't matter. I am using C++11... are move semantics coming into play here?
Temporary cannot be bind to non const reference, change SetVarC to
void A::SetVarC(const coord<int>& c)
{
m_c = c;
}
or
void A::SetVarC(coord<int> c)
{
m_c = std::move(c);
}
You are passing a temporary coord<int> object to A::SetVarC() which requires a non-const reference, which is not possible.
You should fix your code by changing A::SetVarC() to accept a const coord<int>&.
You're creating arithmetic operators with a side affect...
These operators shouldn't change the value of the arguments used.
And, to the answer your question, these methods return a temporary object, that can't be passed as reference to SetVarC.
template<typename T = int>
inline coord<T> operator-(const coord<T>& lhs, const coord<T>& rhs)
{
coord<T> res(lhs)
res -= rhs;
return res;
}
template<typename T = int>
inline coord<T> operator+(const coord<T>& lhs, const coord<T>& rhs)
{
coord<T> res(lhs)
res += rhs;
return res;
}