Люди смущаются, когда слышат это в
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" относится к категории значений.