0

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?

NeomerArcana
  • 1,978
  • 3
  • 23
  • 50

3 Answers3

5

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);
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302
2

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>&.

cmaster - reinstate monica
  • 38,891
  • 9
  • 62
  • 106
-2

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;
}
Yochai Timmer
  • 48,127
  • 24
  • 147
  • 185
  • 1
    It's perfectly fine modifying an argument passed by value. – Deduplicator Dec 30 '14 at 09:36
  • @Deduplicator yes, but that's not the Meaning of the operator. an operator + between 2 items should return the result of the operation, not change one of the items. To have a clear API you must keep the standard definitions, or else you'll may suffer from side effects that are harder to find. – Yochai Timmer Dec 30 '14 at 10:34
  • 1
    You're returning a reference to a temporary. (also, [see here](http://stackoverflow.com/a/7592741/1012936) for why pass-by-value is reasonable here) – milleniumbug Dec 30 '14 at 10:43
  • @milleniumbug Yes, that was a mistake. – Yochai Timmer Dec 30 '14 at 10:47