After reading this question. I created this small little test:
class A{
public:
A(){}
A(const A&){printf("copy\n");}
A(A&&){printf("move\n");}
static A f(){
A a;
return a;}
static A g(){
A a;
return (a);}//could be return *&a; too.
static A h(){
A a;
return true?a:a;}
};
The result is (without RVO and NRVO):
- f uses move
- g uses move
- h uses copy
As far as I know the rules used to decide whether to use copy or move are described in 12.8.32:
- When the criteria for elision of a copy operation are met or would be met save for the fact that the source object is a function parameter, and the object to be copied is designated by an lvalue, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue. ...
Which refers to the rules of 12.8.31: (I only show the relevant part)
- in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object (other than a function or catch-clause parameter) with the same cvunqualified type as the function return type, the copy/move operation can be omitted by constructing the automatic object directly into the function’s return value
- when a temporary class object that has not been bound to a reference (12.2) would be copied/moved to a class object with the same cv-unqualified type, the copy/move operation can be omitted by constructing the temporary object directly into the target of the omitted copy/move
Following these rules I understand what happens for f and h:
- The copy in f is eligible for elision so it is moved. (cf. the bold part)
- The copy in h is not eligible for elision so it is copied.
What about g?
To me it looks really like h. I am returning an expression which is not the name of an automatic object and as such I thought it would be copied however it is moved. What is going on here?