Ответ 1
Некоторые предварительные параграфы сначала:
[Основная]
3 Сущность - это значение, объект, ссылка, функция, перечислитель, тип, член класса, шаблон, специализация шаблона, пространство имен, пакет параметров или эта.
[dcl.type.simple]
4 Тип, обозначаемый
decltype(e)
, определяется следующим образом:
если
e
- это не выраженное в скобках id-выражение или не заключенное в скобки обращение к члену класса ([expr.ref]),decltype(e)
- это тип сущности, названныйe
. Если такой сущности нет, или если e называет набор перегруженных функций, программа некорректна;в противном случае, если
e
- значение x,decltype(e)
- этоT&&
, гдеT
- типe
;в противном случае, если e - это
decltype(e)
,decltype(e)
- этоT&
, гдеT
- это типe
;в противном случае
decltype(e)
является типомe
.[dcl.ref]
1 В декларации
TD
гдеD
имеет одну из форм& attribute-specifier-seqopt D1 && attribute-specifier-seqopt D1и тип идентификатора в объявлении
T D1
является "производным-декларатором-типом-спискомT
", тогда тип идентификатораD
является "производной-декларатором-тип-ссылкой на списокT
".[выражение]
5 Если выражение изначально имеет тип "ссылка на
T
" ([dcl.ref], [dcl.init.ref]), тип корректируется доT
перед любым дальнейшим анализом. Выражение обозначает объект или функцию, обозначенную ссылкой, и выражение является lvalue или xvalue, в зависимости от выражения.[expr.prim.general]
8 Идентификатор - это id-выражение при условии, что оно было надлежащим образом объявлено (пункт [dcl.dcl]). Тип выражения - это тип идентификатора. Результатом является объект, обозначенный идентификатором. Результатом является lvalue, если объект является функцией, переменной или элементом данных, и prvalue в противном случае.
[expr.call]
10 Вызов функции - это lvalue, если тип результата является ссылочным типом lvalue или ссылкой rvalue на тип функции, xvalue, если тип результата является ссылкой rvalue на тип объекта, и prvalue в противном случае.
Который сейчас позволяет нам отвечать на ваши вопросы.
В строке 1
x
является идентификатором (id-выражением), который называет параметр функции. Его тип -int&&
, и это тип, которыйdecltype(x)
.x
не является выражением и не имеет категории значения.
Да вроде. x
в объявлении не является выражением. Но в качестве аргумента для decltype
используется выражение. Однако он попадает в особый случай первого decltype
поэтому выводится тип идентификатора с именем x
, а не тип x
в качестве выражения.
В строке 2
x
является выражением. Перед настройкой типа его тип являетсяint&&
, а после типа становитсяint
. Категория значения - lvalue.
Да.
В строке 3
std::move(x)
является выражением. Его тип до настройки -int&&
, после -int
. Категория значения - xvalue.
Да.
Когда мы говорим, что
x
имеет ссылочный тип rvalue, мы ссылаемся либо на типx
в качестве идентификатора, либо на типx
в качестве выражения перед настройкой типа.
Да.
Слово "тип" в выражении "Каждое выражение имеет некоторый нереферентный тип, и каждое выражение принадлежит ровно к одной из трех основных категорий значений" на cppreference.com относится к типу после корректировки типа.
Да.
Когда Скотт Мейерс пишет: "Если тип выражения является ссылкой на lvalue (например,
T&
или constT&
и т.д.), То это выражение является lvalue". он относится к типу перед корректировкой, а второе слово "lvalue" относится к категории значений.
Не могу точно сказать, что имел в виду Скотт Мейерс, когда писал это, но это единственная интерпретация слов, которая соответствует стандарту, да.