Люди смущаются, когда слышат это в
int&& x
x
имеет ссылочный тип rvalue, но x
является lvalue. Непонимание связано с тем, что идентификаторы и выражения - это разные вещи, а также типы и категории значений. Кроме того, типы выражений "корректируются до дальнейшего анализа", и слова "rvalue" и "lvalue" могут появляться как в имени типа, так и в имени категории значения.
Я хочу уточнить формальные определения. Предположим, у нас есть функция:
1 | void f(int&& x) {
2 | ... = x;
3 | ... = std::move(x);
4 | }
Правильны ли следующие утверждения?
- В строке 1
x
является идентификатором (id-выражением), который называет параметр функции. Его тип -int&&
, и это тип, которыйdecltype(x)
.x
не является выражением и не имеет категории значения. - В строке 2
x
является выражением. Перед настройкой типа его тип являетсяint&&
, а после типа становитсяint
. Категория значения - lvalue. - В строке 3
std::move(x)
является выражением. Его тип до настройки -int&&
, после -int
. Категория значения - xvalue. - Когда мы говорим, что
x
имеет ссылочный тип rvalue, мы ссылаемся либо на типx
в качестве идентификатора, либо на типx
в качестве выражения перед настройкой типа. - Слово "тип" в выражении "Каждое выражение имеет некоторый нереферентный тип, и каждое выражение принадлежит ровно к одной из трех основных категорий значений" на cppreference.com относится к типу после корректировки типа.
- Когда Скотт Мейерс пишет: "Если тип выражения является ссылкой на lvalue (например,
T&
илиconst T&
и т.д.), То это выражение является lvalue". он относится к типу перед корректировкой, а второе слово "lvalue" относится к категории значений.