Все ли временные значения rvalues в C++?

последние несколько лет я кодирую на C++. Но есть один вопрос, который я не смог выяснить. Я хочу спросить, все ли временные в C++, rvalues?

Если нет, Может ли кто-нибудь предоставить мне пример, где временным произведенным в коде является lvalue?

7 ответов


нет.

спецификация языка C++ никогда не делает такое простое утверждение, как то, о котором вы спрашиваете. В стандарте языка нигде не говорится ,что"все временные объекты являются rvalues". Более того, сам вопрос немного неправильный, так как свойство быть rvalue в языке C++ не является свойством объекта, а скорее свойством выражения (т. е. свойством его результата). Это на самом деле, как это определено в языке спецификация: для различных видов выражений он говорит, когда результат является lvalue и когда это rvalue. Среди прочего, это фактически означает, что временный объект может быть доступен как rvalue, так и lvalue, в зависимости от конкретной формы выражения, которая используется для выполнения доступа.

например, результат literal 2 + 3 выражение, очевидно, является rvalue, временным типом int. Мы не можем применять унарные & с одинарными & требует lvalue в качестве своего операнда

&(2 + 3); // ERROR, lvalue required

однако, как мы все знаем, Постоянная ссылка может быть прикреплена к временному объекту, как в

const int &ri = 2 + 3;

в этом случае ссылка прилагается к временному, продлевая срок службы последнего. Очевидно, как только это будет сделано, у нас будет доступ к тому же временному, что и lvalue ri, так как ссылки всегда lvalues. Например, мы можем легко и легально применять унарные & по ссылке получите указатель на временное

const int *pi = &ri;

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

другим очевидным примером доступа lvalue к временному объекту является доступ к временному объекту типа класса через его this указатель. Результат *this является lvalue (как всегда бывает с результатом унарного * применяется к указателю данных), но это не меняет тот факт, что реальный объект может быть легко времянка. Для данного типа класса T, выражение T() является rvalue, как явным образом указано в стандарте языка, но временный объект доступен через *T().get_this() выражение (с очевидной реализацией T::get_this()) является lvalue. В отличие от предыдущего примера, этот метод позволяет немедленно получить неконст-квалифицированный lvalue, который ссылается на временный объект.

Итак, еще раз, тот же самый временный объект можно легко "увидеть" как rvalue или как lvalue в зависимости от того, какое выражение (какой вид путь доступа) вы используете, чтобы" смотреть " на этот объект.


Prasoon Saurav уже связал очень хороший поток clc++. Там Джеймс канце объясняет, почему этот вопрос на самом деле не имеет смысла. Это сводится к:

  • rvalue-ness является (булевым) свойством выражений-каждое выражение является либо lvalue, либо rvalue
  • временных объектов не выражения

по этой причине, вопрос не имеет смысла.

хороший пример код:

int main() {
  const int& ri = 4;
  std::cout << ri << std::endl; 
}

временный int со значением 4 не является выражением. Выражение ri это напечатано не является временным. Это lvalue, и относится к временному.


ну, этот оператор массива возвращает ссылку, любая функция, которая возвращает ссылку, может рассматриваться как то же самое? все ссылки являются const, хотя они могут быть lvalues, они изменяют то, что они ссылаются, а не саму ссылку. то же самое верно для *оператор

*(a temp pointer) = val;

клянусь, я использовал компилятор, который передавал значения temp любой функции, которая взяла ссылку,

так что вы могли бы go:

int Afunc()
{
   return 5;
}

int anotherFunc(int & b)
{
    b = 34;
}


anotherFunc(Afunc());

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

int anotherFunc(const int & b);

в любом случае, ссылки могут быть lvalues и временными, трюк, являющийся ссылкой, что он сам не изменяется, только то, что он ссылается.

если считать-> оператор как оператор, то временные указатели могут быть lvalues, но то же условие применяется, его не указатель temp, который будет изменен, но то, на что он указывает.


операция индексирования массива является временной и lvalue, что-то вроде[10] = 1 является примером того, что вы ищете; lvalue является временным, вычисленным указателем.


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

интересный ответ: копирование elision может сделать (часто делает) временный объект идентичным объекту lvalue. Например,

MyClass blah = MyClass( 3 ); // temporary likely to be optimized out

или

return MyClass( 3 ); // likely to directly initialize object in caller's frame

Edit: как для вопрос о том, существует ли какой-либо временный объект в этих случаях, упоминается в §12.8/15

операция копирования может быть опущена путем построения временного объекта непосредственно в целевой объект опущенной копии

что указывает на то, что существует временный объект, который может быть идентичен lvalue.


Это зависит от того, что вы считаете временной переменной. Вы можете написать что-то вроде

#include <stdio.h>
int main()
{
    char carray[10];
    char *c=carray+1;
    *(c+2+4) = 9;
    printf("%d\n",carray[7]);
    return 0;
}

это выполняется в VisualStudios и GCC. Вы можете запустить код в codepad

Я считаю (c+2+4)rvalue, хотя я хочу назначить ему. Когда я разыграю ее, она станет lvalue. Так что да, все временные-это rvalues. Но вы можете сделать rvalues (таким образом, временный) в lvalue, разыменовав его


если нет, Может ли кто-нибудь предоставить мне пример, где временное произведенное в коде является lvalue?

следующий код связывает константную ссылку на временный объект типа const float созданный компилятором:

int i;
const float &cfr = i;

поведение "как будто":

int i;
const float __tmp_cfr = i; // introduced by the compiler
const float &cfr = __tmp_cfr;