After much reading I came to the following conclusions:
lvalue
( locator value ):
Denotes an addressable value.
A value whose address can be directly obtained (through the &
operator).
int a = 3;
int& b = a;
a // é lvalue
b // é lvalue
&a // não é lvalue (o ponteiro retornado é um temporário, não pode fazer &&a)
3 // não é lvalue (3 é também um temporário)
2+1 // não é lvalue (idem)
const int& c = 2+1; // Uma referência constante conectada um temporário estende
// sua vida pela vida da referencia. "Dar um nome ao temporário".
c; // é lvalue
struct S {
int data = 42;
S* self() { return this; }
S& operator=(int a) { data = a; return *this; }
};
(S()) // não é um lvalue (embora esteja na memória e tenha endereço this)
(*S().self()) // é um lvalue (exatamente igual ao anterior, mas dessa vez é um lvalue)
(S() = 5) // não é um lvalue (note que assignment é só uma chamada ao 'operator=')
(S().data) // não é um lvalue
(S().self()->data) // é um lvalue
xvalue
( expiring value ):
Denotes a value whose life must end at the end of the expression. It is an indication that data can be moved (interferes with the resolution of overloaded functions).
The return value of a function if this returns a &&
reference to an object or the conversion of an object to a &&
reference.
int&& func() { return 3; }
func() // é um xvalue
((int&&)3) // é um xvalue
S s;
std::move(s) // é um xvalue (std::move não move! É só um cast)
((S&&)s).data // é um xvalue
int&& d = 3; // vida do temporário é estendida
d // é um lvalue (qualquer coisa que tenha um nome é um lvalue, 'd' é um nome)
prvalue
( pure rvalue ):
Denotes a temporary that is not a xvalue
.
A value that is not a lvalue
nor a xvalue
.
// qualquer expressão constante é um prvalue
3 // é um prvalue
1+2 // é um prvalue
sizeof(int) // é um prvalue
nullptr // é um prvalue
!true // é um prvalue
[](int a){ return a+1; } // é um prvalue
// uma função retornando um objeto que não seja referência
// uma conversão para um tipo que não seja referência
int func2 { return 3; }
func2() // é um prvalue
float(3); // é um prvalue
float(func2()) // é um prvalue
rvalue
:
Denotes values for which to create a pointer does not make sense. The end of the object's life is eminent or temporary.
A value that is not a lvalue
(that is, a xvalue
or a prvalue
)
glvalue
( generalized lvalue ):
Denotes everything that is not a temporary. That is, everything for which a reference can be constructed (this way: type& var = glvalue
).
A value that is not a prvalue
(that is, a xvalue
or a lvalue
)
Note that even with the creation of new types, a value is always a lvalue
OR a rvalue
. The last two classifications probably exist to make generalizations within other rules of the standard.