2017-02-03 5 views
3

Предположим, что m является нестационарным элементом данных без ссылочного типа (T). Согласно cppreference, std::move(a).m является prvalue до C++ 11. Я думаю, это должно быть xvalue после C++ 11. Пожалуйста, поправьте меня, если я ошибаюсь.Является std :: move (a) .m xvalue или prvalue?

Но decltype(std::move(a).m) еще T (не T&&) в C++ 14 (Visual Studio, лязг, НКУ), которые предполагают std::move(a).m еще prvalue. Итак, std::move(a).m xvalue или prvalue?

+0

* «Я предполагаю, что это должно быть xvalue после C++ 11» * Зачем угадывать? В той же самой статье прямо сказано. –

+2

'decltype (std :: move (a) .m)' вероятно, подпадает под «выражение без доступа к члену класса» [специальный случай] (http://en.cppreference.com/w/cpp/language/decltype) –

+0

' expression_name' может рассказать вам, что ваш компилятор думает об этом: http://stackoverflow.com/a/20721887/576911 Мой компилятор согласен с Барри. –

ответ

2

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&&.

+0

Так почему же 'T()' не имеет идентификатора, а 'T(). E' does? –

+0

@ T.C. Имя. 'T()' не имеет имени, 'T(). E' is' e'. – Barry

+0

Я не уверен, что покупаю это. Независимо от того, возьмите 'T' =' int [2] 'и сравните' T {} 'и' T {} [1] '. –

Смежные вопросы