c++ - ¿Por qué el resultado de "decltype(i+j)" no es una referencia de valor?
c++11 rvalue-reference (2)
Basándome en la Answer @ songyuanyao, noté que mi error fue verificar algo incorrecto: mi intención era verificar si el resultado de i+j
uniría a una referencia de valor r, pero verifiqué si es una referencia de valor r.
decltype deduce el tipo basado en la categoría de valor , no en función del tipo de referencia al que se uniría el valor:
1) si la categoría de valor de expresión es
xvalue
, entonces decltype produceT&&
;
2) si la categoría de valor de expresión eslvalue
, entonces decltype produceT&
;
3) si la categoría de valor de expresión esprvalue
, entonces decltype produceT
Como se muestra en la lista, desde C ++ 11, los rvalues
no existen como una categoría distinta en el nivel más bajo. Ahora son una categoría compuesta que contiene prvalues
y xvalues
. La pregunta tal como está escrita pregunta si la expresión es una rvalue reference
y verifica si es un valor xvalue
.
De la lista anterior, está claro que i+j
es un prvalue
, por lo que se aplica el tercer caso. Esto explica por qué decltype(i + j)
es int
y no int&&
. Tanto xvalues
como prvalues
unen a las referencias de rvalue.
Entonces, al verificar si i+j
une a una lvalue reference
rvalue reference
o una rvalue reference
confirma que, de hecho, se une a una rvalue reference
:
void foo(const int& f)
{
std::cout << "binds to lvalue reference" << std::endl;
}
void foo(int&& f)
{
std::cout << "binds to rvalue reference" << std::endl;
}
void test(int i, int j)
{
foo(i); // lvalue -> lvalue ref
foo(std::move(i)); // xvalue -> rvalue ref
// (std::move converts the argument to a rvalue reference and returns it as an xvalue)
foo(i + j); // prvalue -> rvalue ref
}
En conclusión: i+j
no es una referencia rvalue, pero se une a uno.
Estoy tratando de dar un ejemplo simple para una operación que dé como resultado un valor.
Este caso de prueba debería haber funcionado, pero sorprendentemente (para mí), el resultado de agregar dos int
s no es un valor (referencia). ¿Que me estoy perdiendo aqui?
void test(int i, int j)
{
// this assert should pass, but fails:
static_assert(std::is_same<decltype(i + j), int&&>(), "i + j should be a rvalue");
// this assert passed, but should fail:
static_assert(std::is_same<decltype(i + j), int>(), "this assert should fail...");
}
i + j
es una expresión prvalue ,
Una expresión prvalue ("pure rvalue") es una expresión que no tiene identidad y se puede mover desde.
a + b, a% b, a & b, a << b, y todas las demás expresiones aritméticas integradas;
no es un xvalue ,
Una expresión xvalue ("valor que expira") es una expresión que tiene identidad y se puede mover desde.
Y el especificador decltype produce T
para prvalue, no T&&
.
a) si la categoría de valor de la expresión es xvalue, entonces decltype produce T &&;
b) si la categoría de valor de la expresión es lvalue, entonces decltype produce T &;
c) si la categoría de valor de expresión es prvalue, entonces decltype produce T.
Puedes hacerlo xvalue por std::move
:
static_assert(std::is_same<decltype(std::move(i + j)), int&&>(), "std::move(i + j) is a xvalue then this static_assert won''t fail");