Почему именованная ссылка rvalue является выражением lvalue? - PullRequest
3 голосов
/ 26 мая 2019

Я знаю, что именованная ссылка является lvalue:

int x = 1;
int& ref1 = x;
int&& ref2 = std::move(x);

Я прочитал объяснение & mdash; это потому, что мы можем взять адрес этих ref1 и ref2.

Но когда мы берем адрес ссылки, мы фактически берем адрес объекта, на который ссылаемся, не так ли? Так что это объяснение не похоже на правильное.

Так почему именованная ссылка является lvalue?

Ответы [ 3 ]

3 голосов
/ 27 мая 2019

Per [expr.prim.id.unqual] (8.1.4.1 Неквалифицированные имена):

[...] Выражение является lvalue, если объектфункция, переменная или член данных и значение в противном случае;это битовое поле, если идентификатор обозначает битовое поле ([dcl.struct.bind]).

Per [basic] / 6 :

A переменная вводится путем объявления ссылки, отличной от нестатического члена данных или объекта.Имя переменной, если она есть, обозначает ссылку или объект.

Объявление

int&& ref2 = std::move(x);

является «объявлением ссылки, отличной от нестатического элемента данных».Следовательно, сущность, обозначенная ref2, является переменной.Таким образом, выражение ref2 является lvalue.

2 голосов
/ 27 мая 2019

Это объяснение просто упрощение. lvalues ​​определяется не как «то, что вы можете взять по адресу», а по определенному набору правил относительно категории значений выражений. Эти правила тщательно сконструированы таким образом, чтобы в результате появился самосогласованный язык, в котором все достаточно аккуратно соединяется.

Как уже говорилось, объяснение подходит здесь вполне уместно, если учесть, что, написав ref1, вы на самом деле не называете «ссылку», но вещь, на которую ссылаются. В этом волшебство ссылок: вы должны рассматривать их как псевдонимы имен, а не как отдельные сущности.

Есть некоторые утечки абстракции, связанные с этим (в частности, ссылки на членов), но это суть.

Вам следует забыть о таких понятиях, как «ссылка является lvalue» и вместо этого подумать о выражениях . Объекты имеют типы; выражения имеют категории значений.

0 голосов
/ 27 мая 2019

Вот объяснение из книги Скотта Мейерса «Эффективный современный C ++»:

На самом деле, T&& имеет два разных значения. Одним из них является, конечно, ссылка. Такие ссылки ведут себя точно так, как вы ожидаете: они привязываются только к r-значениям, и их основной смысл состоит в том, чтобы идентифицировать объекты, которые могут быть перемещены из.

void f(Widget&& param); // rvalue reference

Widget&& var1 = Widget(); // rvalue reference

auto&& var2 = var1; // not rvalue reference

template<typename T>
void f(std::vector<T>&& param); // rvalue reference

template<typename T>
void f(T&& param); // not rvalue reference

Другое значение для T&& является либо ссылкой на значение, либо ссылкой на значение. Такие ссылки выглядят как ссылки на rvalue в исходном коде (т. Е. T&&), но они могут вести себя так, как если бы они были ссылками на lvalue (т. Е. T&). Их двойственная природа позволяет им связываться с r-значениями (такими как ссылки на r-значения), а также с l-значениями (например, ссылки на l-значения). Кроме того, они могут связываться с const или не- const объектами, volatile или не- volatile объектами, даже с объектами const и volatile. Они могут связываться практически с чем угодно. Такие беспрецедентно гибкие ссылки заслуживают собственного имени. Я называю их универсальными ссылками.

...