This program:
#include <iostream>
struct T {
T() {}
T(const T &) { std::cout << "copy constructor "; }
T(T &&) { std::cout << "move constructor "; }
};
int main() {
([](T t) -> T { return t; })({}); std::cout << '\n';
([](T t) -> T { return void(), t; })({}); std::cout << '\n';
([](T t) -> T { return void(), std::move(t); })({}); std::cout << '\n';
}
when compiled by gcc-4.7.1 outputs (link):
move constructor
copy constructor
move constructor
Why does the comma operator have this effect? The standard says:
5.18 Comma operator [expr.comma]
1 – […] The type
and value of the result are the type and value of the right operand; the result is of the same value category as its right operand […]. If the value of the right operand is a temporary, the result is that temporary.
Have I missed something that allows the comma operator to affect the semantics of the program, or is this a bug in gcc?
Automatic move is based on eligibility for copy elision:
§12.8 [class.copy] p32And copy elision in turn is allowed when the return expressions is the name of an automatic object.
§12.8 [class.copy] p31With the comma operator inserted, the expression is not the name of an automatic object anymore, but only a reference to one, which suppresses copy elision.