Подтвердить что ты не робот

Переместить конструктор, подавленный оператором запятой

Эта программа:

#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';
}

при компиляции выводами gcc-4.7.1 (ссылка):

move constructor 
copy constructor 
move constructor 

Почему оператор запятой обладает этим эффектом? В стандарте говорится:

5.18 Comma operator [expr.comma]

1 - [...] Тип и значение результата - это тип и значение правого операнда; результат имеет ту же категорию значений, что и ее правый операнд [...]. Если значение правильного операнда является временным, результатом является временное.

Я пропустил что-то, что позволяет оператору запятой влиять на семантику программы, или это ошибка в gcc?

4b9b3361

Ответ 1

Автоматическое перемещение основано на праве на копирование:

§12.8 [class.copy] p32

Когда критерии для выполнения операции копирования выполняются или выполняются, за исключением того факта, что исходный объект является параметром функции, а подлежащий копированию объект определяется значением lvalue, разрешением перегрузки, чтобы выбрать конструктор для копия сначала выполняется так, как если бы объект был обозначен rvalue. [...]

И копирование elision в свою очередь разрешено, когда возвращаемые выражения являются именем автоматического объекта.

§12.8 [class.copy] p31

в операторе return в функции с типом возвращаемого класса , когда выражение является именем энергонезависимого автоматического объекта (кроме функции или параметра catch-clause) с тот же cv-неквалифицированный тип, что и возвращаемый тип функции, операцию копирования/перемещения можно опустить, построив автоматический объект непосредственно в возвращаемое значение функции

С введенным оператором запятой выражение больше не является именем автоматического объекта, а только ссылкой на него, которое подавляет копирование.

Ответ 2

t - это локальная переменная с именем, и, следовательно, lvalue. Оператор запятой ведет себя как задокументированный.

Скорее вы должны спросить, почему return t; позволяет t связываться с ссылкой на rvalue - это настоящая магия.