Верно ли, что переменные, адрес которых можно взять, являются lvalue?

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

Предположим, у меня есть следующий код

class Test
{
};
int main()
{
   std::cout << "Address is " << &(Test()) << std::endl;
   Test() = Test();
   Test&& t = Test();
   return 0;
}

В приведенном выше случае Test () является временным, то есть rvalue, и я могу взять его адрес (с gcc мы можем использовать -fpremissive, а с msvc он будет компилироваться напрямую), поэтому с этим мы можем сказать, что это lvalue, а также bcoz мы можем сделать Test() = Test(), но поскольку мы можем использовать ссылку rvalue, это должно быть rvalue.

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


person PapaDiHatti    schedule 18.05.2016    source источник
comment
Для вашего второго случая вы можете взглянуть на stackoverflow.com/questions/2145030/.   -  person Holt    schedule 18.05.2016
comment
Да, я беру адрес y, но это не компиляция, и поэтому я спрашиваю, является ли y lvalue, почему я не могу взять адрес y   -  person PapaDiHatti    schedule 18.05.2016
comment
Также предполагая, что Test() является lvalue, тогда как я могу использовать ссылку rvalue на него как Test&& t = Test(); правильно компилируется   -  person PapaDiHatti    schedule 18.05.2016
comment
переменная не может быть lvalue; lvalue — это разновидность выражения. (Имя переменной является lvalue.)   -  person Keith Thompson    schedule 19.05.2016


Ответы (2)


Ваш первый код неверен, потому что объявление z должно быть int*, этот код компилируется и работает нормально:

int x = 12;  // x is lvalue
int& y = x;  // y is lvalue reference
int *z = &y; // can take address of lvalue reference (address of the referenced)
assert(z == &x);

Для вашего второго примера Test() на самом деле является prvalue, и вы не можете использовать его адрес переносимым способом, как указано в стандарте.

У MSVC есть расширения, которые позволяют вам брать адрес prvalues, а GCC позволяет вам включить такое расширение, используя -fpermissive:

Понизьте некоторые средства диагностики несовместимого кода с ошибок до предупреждений. Таким образом, использование -fpermissive разрешит компилировать некоторый несоответствующий код.

Это означает, что Скотт Мейерс прав, а составители ошибаются, по крайней мере, в вопросе соответствия стандарту. Кроме того, передав -fpermissive, вы сказали gcc быть менее строгим, т.е. разрешить компилировать ваш несоответствующий код. Для полного соответствия вы всегда должны компилировать с -pedantic или -pedantic-errors (поскольку, как и MSVC, gcc по умолчанию также включает некоторые языковые расширения).

person Holt    schedule 18.05.2016
comment
Спасибо, я удалил первую часть, так как она была неверной, но, основываясь на ваших предыдущих комментариях, я могу скомпилировать Test() = Test() без каких-либо расширений. То есть это rvalue также может появиться слева, и тогда почему 2 = 2 будет не компилируется в С++? - person PapaDiHatti; 18.05.2016
comment
@Kapil Мой последний комментарий был ошибочным (извините), rvalue как-то плохое имя. Test() = Test() в основном Test().operator=(Test()), и нет ничего плохого в вызове метода для rvalue. - person Holt; 18.05.2016

На основании комментариев от holt и поскольку я отредактировал вопрос, поэтому я думаю, что правильным ответом должен быть Test () в приведенном выше контексте, это rvalue, и если мы используем стандартизированный компилятор, этот код не будет компилироваться, поэтому, если ваш код компилируется, это означает либо флаг fpermissive установлен в gcc или с msvc, ваши настройки позволяют вам заставить это работать. Вторая строка Test() = Test() работает, потому что она эквивалентна Test().operator=() и мы можем вызывать функцию из rvalue. Теперь третья строка является неявной, поскольку это rvalue, поэтому мы можем иметь ссылку на rvalue.

Следовательно, этот пример доказывает, что мы можем получить адрес lvalue только при условии, что мы используем стандартизированный компилятор.

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

person PapaDiHatti    schedule 18.05.2016