В каком случае всегда используется lvalue для доступа к члену ссылочного типа?

Почему не следует применять правило для доступа к членам класса с выражением объекта xvalue [expr] /7.3 к ссылочным типам?

Вместе с [expr.ref] / 4

«Если объявлено, что E2 имеет тип« ссылка на T », тогда E1.E2 - это lvalue; тип E1.E2 - T.»

информация об истечении срока действия изменена без очевидной причины.

Кто-нибудь знает причину этого решения?

#include <utility>

int i;
struct { int && m; } a { std::move (i) };
typedef decltype ((std::move (a).m)) M; 

// M is int &, not &&
static_assert ((std::is_same <M, int &>::value), ""); 

int main () {}

Я предполагаю, что меня беспокоит в первую очередь то, что это нарушает тривиальное решение для пересылки членов класса:

template <typename U> auto f (U && u) 
 -> decltype ((static_cast <U &&> (u).m))
{
    return     static_cast <U &&> (u).m;    
}

без каких-либо очевидных альтернатив, за исключением обращения к более сложным решениям свойств типов.


person listcrawler    schedule 10.03.2016    source источник


Ответы (2)


Если вы рассмотрите различия между lvalues ​​и glvalues, а также то, что имеет смысл, чтобы член struct X { T& r; }; мог произойти с указанным значением:

  • lvalues ​​никогда не могут быть перемещены, поэтому вы не можете случайно перейти от переменной, на которую ссылается член, что безопаснее, поскольку на одну и ту же переменную можно ссылаться из многих мест, и они, предположительно, предназначены для взаимодействия / координации каким-либо образом: семантика не кооперативна, поскольку неопределенное значение оставленного значения

  • lvalue могут иметь свой адрес: почему вы не можете получить адрес переменной, на которую указывает ссылка?

  • вы можете создавать новые ссылки на lvalue: заставляя их ссылаться на одну и ту же переменную X::r ссылки

person Tony Delroy    schedule 10.03.2016

Это согласуется с обработкой id-выражений, которые не являются правильным операндом выражения доступа к члену класса ([expr.prim.general] / 8):

int&& i = 0; // i is an lvalue
void f(int&& j) { /* j is an lvalue */ }
struct S { int&& k; void g() { /* k is an lvalue */ } };

В частности, обратите внимание на последний случай; k было бы очень запутанно назначать lvalue внутри функций-членов S, а s.k - обозначать xvalue снаружи.

Что касается того, почему id-выражения обрабатываются как lvalue, даже если они объявили ссылку типа rvalue на T, на этот вопрос уже был подробно дан ответ ранее; см. например О том, как распознать ссылку Rvalue или Lvalue и правило, если у него есть имя.

person ecatmur    schedule 10.03.2016
comment
Может быть, лучше сформулировать мой вопрос: почему правило доступа к членам класса с выражением объекта xvalue [expr] /7.3 не должно применяться к ссылочным типам? Вместе с [expr.ref] / 4, упомянутым выше, информация об истечении срока действия изменяется без очевидной причины. Улучшение моего первоначального вопроса с этим. - person listcrawler; 10.03.2016
comment
@listcrawler, если класс имеет член ссылочного типа, он предположительно ссылается на какой-то объект вне класса, поэтому категория значения выражения объекта не влияет на время жизни референта. - person ecatmur; 10.03.2016
comment
Это правильное замечание, возвращая членов класса ссылочного типа в связку if-it-has-a-name. Думаю, я пока отложу это, добавив в свой первоначальный квест примечание о переадресации участников, почему это меня вообще обеспокоило. - person listcrawler; 10.03.2016