std::move(a).m
является xvalue.
новых формулировок сделать это гораздо яснее, в [basic.lval]:
- prvalue это выражение, оценка инициализирует объект или битовое поле, или вычисляет значение операнд оператора, как определено контекстом, в котором он появляется.
- xvalue - это значение glvalue, которое обозначает объект или бит-поле, ресурсы которого могут быть повторно использованы (как правило, потому, что он близок к концу его жизни).
По этим определениям, std::move(a).m
является xvalue, а не prvalue как это обозначает объект.
Способ, которым я нахожусь лучше всего думать об этом, состоит в том, что glvalues имеют идентичность и значения, которые можно безопасно перемещать из - где lvalues имеют идентичность и не безопасны для перемещения, xvalues имеют личность и безопасны для перемещения, а prvalues не имеют идентичности и безопасны для перемещения. Эта таксономия упрощает такие вопросы.
Кроме того, существует примечание в [выражение], более конкретно:
[Примечание: Выражение является xvalue, если оно: [...]
- литая к RValue ссылка на объект типа,
- выражение доступа члена класса, обозначающее нестатический элемент данных не-опорный типа, в котором выражение объекта является xvalue, или [...]
-end примечание]
std::move(a)
- это ссылка на значение rvalue, а также значение xvalue. std::move(a).m
- это доступ класса к значению x, так что значение xvalue.
Что касается decltype(std::move(a).m)
. Обратите внимание, что само слово происходит от decl ared тип. Правила для того, что означает decltype(e)
, сложны, из [dcl.type.простой]:
Для выражения e
, тип обозначается decltype(e)
определяются следующим образом:
- если e
является заключённым в скобках ID выражения именования именующего выражения или ссылки на введенном из идентификатора-списка объявления декомпозиции, decltype(e)
является ссылочным типом, указанным в спецификации объявления декомпозиции (8.5);
- иначе, если e
является идентификатора заключённого в скобках выражениеили доступ к члену в скобках, класса (5.2.5), decltype(e)
является типом объекта, названного e
. Если такой объект отсутствует или e
называет набор перегруженных функций, программа плохо сформирована;
- в противном случае, если e
является xvalue, decltype(e)
является T&&
, где T
- тип e
;
- в противном случае, если e
является lvalue, decltype(e)
является T&
, где T
- тип e
;
- в противном случае, decltype(e)
- это тип e
.
В этом случае мы имеем доступ к членам класса, так что вы просто получить тип m
- который M
и не M&&
. На каком-то уровне это имеет смысл, вы просите объявленный тип m
, и вы получили объявленный тип m
.
Если вы хотите категоризировать его должным образом, вы можете заставить эту пулю игнорировать дополнительный набор круглых скобок (очевидно): decltype((std::move(a).m))
даст вам M&&
.
* «Я предполагаю, что это должно быть xvalue после C++ 11» * Зачем угадывать? В той же самой статье прямо сказано. –
'decltype (std :: move (a) .m)' вероятно, подпадает под «выражение без доступа к члену класса» [специальный случай] (http://en.cppreference.com/w/cpp/language/decltype) –
' expression_name' может рассказать вам, что ваш компилятор думает об этом: http://stackoverflow.com/a/20721887/576911 Мой компилятор согласен с Барри. –