I can't quite figure out why a copy is occurring here. Consider the following:
#include <iostream>
struct X {
X() = default;
X(int value) : value(value) {}
X(const X &x) : value(x.value) {
std::cout << "copy" << std::endl;
}
int value = 0;
};
struct Z {
Z(const X &x) : x(x) {}
const X &get_x() const {return x;}
X x;
};
X get_x(const Z &z) {
return z.get_x();
}
int main() {
X x1(2);
Z z1(x1);
std::cout << "----" << std::endl;
const X &x2 = (true) ? z1.get_x() : get_x(z1); // (1)
std::cout << "----" << std::endl;
const X &x3 = (true) ? z1.get_x() : z1.get_x(); // (2)
}
The output is:
copy
----
copy
----
Why does a copy occur when the result of the false statement changes from a function returning a copy vs a function returning a const-reference, when both should take the true condition? I would have thought that in both (1) and (2), whatever is in the false condition should not have a side effect.
The type, and more importantly here the value category of ? :
has to be determined at compile-time.
If both operands are lvalues, then the result is also an lvalue, and all is well (no extra copy).
But if one operand is a prvalue (aka a temporary object), then the whole ? :
must also return a prvalue. So if the branch taken is originally not a prvalue, a temporary object must be constructed to get one, hence a copy.
Note that I'm intentionally wording this in terms of value categories, rather than reference-ness of types, because expressions can't have refernece types.