Validez de presentar un xvalor como un lvalor.
La siguiente función (en mi intención) toma un rvalue y lo presenta como si fuera un lvalue.
auto constexpr RtoL = [](auto&& r) -> decltype(auto) {
static_assert(std::is_rvalue_reference_v<decltype(r)>, “Gimme rvalues, not lvalues.”);
return (r);
};
Pienso en usarlo en situaciones en las que puedo garantizar que un xvalue no ha sido realmente movido (por ejemplo, fue convertido a rvalue a través de std::move, pero nada aprovechó eso), así que lo llamaría con xvalues, no prvalues.
De todas formas, los compiladores (bueno, las versiones de GCC) parecen tener diferentes opiniones sobre la validez del código anterior. Específicamente, dada esta utilización:
int main() {
int x{3};
RtoL(std::move(x));
}
GCC 11.2 lo considera inválido:
mientras que GCC 10.3 y otros compiladores lo consideran válido.
Además, cambiar la sentencia de retorno de
return (r);
a
return static_cast<decltype(r)&&>(r);
hace que todos ellos estén de acuerdo en que el código es correcto.
¿Dónde está la verdad, desde el punto de vista del estándar?</decltype(r)&&></decltype(r)>
davy.ai
Según el estándar C++17 ([expr.prop]/6), un xvalue es “un glvalue que denota un objeto cuyos recursos pueden ser reutilizados”. Al llamar a
std :: move
en un lvalue, devuelve un xvalue que permite emplear la semántica de movimiento potencialmente más barata, pero no necesariamente significa que los recursos se hayan movido realmente del objeto. Por lo tanto, utilizar un xvalue como lvalue debería ser válido.El estándar también dice que “Un glvalue de un tipo T no de función ni de arreglo puede ser convertido explícitamente a un prvalue.” ([conv.lval]/2) Esta conversión se realiza al devolver
r
desde la lambda, pero el tipo de retorno dedecltype (auto)
conserva la categoría de valor del argumento. Por lo tanto, en la implementación original deRtoL
,r
se devuelve como un lvalue cuando se pasa como un xvalue.El hecho de que GCC 11.2 rechace el código original mientras que GCC 10.3 y otros compiladores lo acepten sugiere que esto podría ser un error de regresión en GCC 11.2. Cambiar la declaración de retorno a
return static_cast<decltype(r)&&>(r)
convierte explícitamente la categoría de valor der
en un rvalue, lo que permite aplicar una semántica de movimiento eficiente si es posible. Esta implementación alternativa también debería ser válida según el estándar, ya que devuelve un rvalue.</decltype(r)&&>