Overloading + problems in complex expressions

I have a class that represents 3D vectors. It has several member functions (dot product, cross product, etc.) as well as several overloaded operators (+ - * /). I am having problems using these operators in complex expressions.

In a simplified test case, if I overload the operator as

testclass operator+ (testclass& a, testclass& b) {
    return testclass(a.get()+b.get());
}

      

I can do

testclass a = testclass(3);
testclass b = testclass(4);
testclass c = a + b;

      

no problem, however more complex expression

testclass c = a + b + a + b;

      

won't compile. I can fix the problem by changing the overload function to

testclass operator+ (testclass a, testclass b) {
    return testclass(a.get()+b.get());
}

      

however, this involves passing by value, which I understand is slower than the referencing scheme in the first case. I use this class for a piece of math intensive code, and my actual class contains three long doubles as data items, so I suspect the performance impact can be significant.

My questions:

  • Why is this behavior happening?
  • Can I avoid this without resorting to passing by value?
  • Passing by value rather than by reference affects performance anyway when I have three long doubles as data items? Will the optimizing compiler (g ++ -O3) optimize it?

Thanks everyone in advance.

Exact compilation error:

operator_overload.cpp: In function ‘int main()’:
operator_overload.cpp:37:29: error: no match foroperator+’ (operand types are ‘testclass’ and ‘testclass’)
         testclass c = a + b + a + b;
                             ^
operator_overload.cpp:37:29: note: candidate is:
operator_overload.cpp:30:15: note: testclass operator+(testclass&, testclass&)
     testclass operator+ (testclass& a, testclass& b) {
           ^
operator_overload.cpp:30:15: note:   no known conversion for argument 1 from ‘testclass’ to ‘testclass&’

      

My complete test code looks like this:

#include <iostream>

class testclass {
public:
    testclass();
    testclass(int);
    int get();
    void set(int);
private:
    int data;
};

testclass::testclass() {
    data = 0;
}

testclass::testclass(int a) {
    data = a;
}

int testclass::get() {
    return data;
}

void testclass::set(int a) {
    data = a;
    return;
}

testclass operator+ (testclass& a, testclass& b) {
    return testclass(a.get()+b.get());
}

int main () {
    testclass a = testclass(3);
    testclass b = testclass(4);
    testclass c = a + b + a + b;
    std::cout << c.get() << std::endl;
    return 0;
}

      

+3


source to share


2 answers


The problem is that rvalues ​​cannot be bound to lvalue references. Intermediate results in a + b + a + b

, say a+b

, are temporary and the full expression does not work. OTOH, const references can bind to rvalues. Change the signature to testclass operator+ (const testclass& a, const testclass& b)

to resolve this issue.



For the above signature to make sense, you also need to have a testclass::get

method const

.

+3


source


You need to use const constructors to hold ref to rvalue

code:



#include <iostream>

class testclass {
public:
    testclass();
    testclass(int);
    int get() const;
    void set(int);
private:
    int data;
};

testclass::testclass() {
    data = 0;
}

testclass::testclass(int a) {
    data = a;
}

int testclass::get() const {
    return data;
}

void testclass::set(int a){
    data = a;
    return;
}

testclass operator+ (const testclass& a, const testclass& b) {
    return testclass(a.get()+b.get());
}

int main () {
    testclass a = testclass(3);
    testclass b = testclass(4);
    testclass c = a + b + a + b;
    std::cout << c.get() << std::endl;
    return 0;
}

      

works for me, gcc 4.9.2

+1


source







All Articles