es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

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::9:14: error: cannot bind rvalue reference of type ‘int&&’ to lvalue of type ‘int’
9 | return (r);
| ^

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)>

Tags:  , , , ,

Answer

  1. Avatar for 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 de decltype (auto) conserva la categoría de valor del argumento. Por lo tanto, en la implementación original de RtoL, 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 de r 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)&&>

Comments are closed.