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

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

#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 Оператор запятой [expr.comma]

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

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

13

Решение

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

§12.8 [class.copy] p32

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

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

§12.8 [class.copy] p31

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

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

14

Другие решения

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

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

8

По вопросам рекламы [email protected]