Why does this C++ snippet assigning a value to an rvalue compile?

a*b = c; calls the assignment operator on the Rational returned by a * b. The assignment operator generated is the same as if the following were defined:

Rational& Rational::operator=(const Rational&) = default;

There is no reason why this shouldn't be callable on a temporary Rational. You can also do:

Rational{1,2} = c;

If you wanted to force the assignment operator to be callable only on lvalues, you could declare it like this, with a & qualifier at the end:

Rational& operator=(const Rational&) &;

"a*b is an r-value, and hence have no location in memory" it is not quite right.

I add prints. The comments are the prints for each line of code

#include <iostream>
using namespace std;

struct Rational {
    
    Rational(int numer, int denom) : numer(numer), denom(denom) {
        cout << "object init with parameters\n";
    }

    Rational(const Rational& r)
    {
        this->denom = r.denom;
        this->numer = r.numer;
        cout << "object init with Rational\n";
    }
    ~Rational() {
        cout << "object destroy\n";
    }

    int numer, denom;
};

Rational operator*(const Rational& lhs, const Rational& rhs) {
    cout << "operator*\n";
    return Rational(lhs.numer * rhs.numer, lhs.denom * rhs.denom);
}

int main() {
    Rational a(1, 2), b(3, 4), c(5, 6); // 3x object init with parameters
    cout << "after a, b, c\n"; // after a, b, c
    Rational d = a * b = c; // operator*, object init with parameters, object init with Rational, object destroy

    cout << "end\n"; // end
    // 4x object destroy 
}

In the line Rational d = a * b = c; d is equal to c. This line call operator* function, that call the object init with parameters constructor. After that c object is copied to d object by calling copy constructor.

If you write the line: Rational d = a = c; // d == c // print only: object init with Rational the compiler assign the d object only to the last assign (object c)

Tags:

C++