¿Por qué std :: declval agrega una referencia?

std::declval es una utilidad de tiempo de comstackción utilizada para construir una expresión con el fin de determinar su tipo. Se define así:

 template typename std::add_rvalue_reference::type declval() noexcept; 

¿No sería esto más simple en su lugar?

 template T declval() noexcept; 

¿Cuál es la ventaja de un tipo de retorno de referencia? ¿Y no debería llamarse declref ?

El primer ejemplo histórico que encuentro es n2958 , que llama a la función value() pero ya siempre devuelve una referencia.

Tenga en cuenta que el operando de decltype no necesita tener un destructor accesible, es decir, no se verifica semánticamente como una expresión completa.

 template t declprval() noexcept; class c { ~ c (); }; decltype ( declprval() ) * p = nullptr; // OK 

La regla “no temporal se introduce para la función que devuelve el prvalor del tipo de objeto en tipo de decltype ” solo se aplica si la función llamada en sí misma es el operando de tipo decltype o el operando derecho de un operador de coma, que es el operando de tipo decltype (§5.2.2 [expr .call] / p11), lo que significa que se ha dado declprval en el OP,

 template< typename t > t declprval() noexcept; class c { ~ c (); }; int f(c &&); decltype(f(declprval())) i; // error: inaccessible destructor 

no comstack Más generalmente, devolver T evitaría la mayoría de los usos no triviales de declval con tipos incompletos, tipo con destructores privados y similares:

 class D; int f(D &&); decltype(f(declprval())) i2; // doesn't compile. D must be a complete type 

y hacerlo tiene poco beneficio ya que los valores de x son prácticamente indistinguibles de los valores de prorrateo, excepto cuando se usa decltype en ellos, y generalmente no se usa decltype directamente en el valor de retorno de declval , ya se conoce el tipo.

Las matrices no pueden devolverse por valor, por lo que incluso la statement de una función que devuelve una matriz por valor no es un código válido.

Sin embargo, puede devolver una matriz por referencia.

El propósito de decltype() es tener una expresión que actúe como un valor válido de tipo T , para ponerla como una T en expresiones que esperan T s. El problema es que en C ++ un tipo T puede ser no copiable, o incluso no constructible por defecto. Así que usar la T{} para ese propósito no funciona.

Lo que hace decltype() es devolver una referencia-rvalue a una T Una referencia rvalue debe ser válida para cualquier tipo T , por lo que se garantiza que tenemos una T válida desde una referencia rvalue de T , y se garantiza que podemos tener una referencia rvalue para cualquier tipo T Ese es el truco.

Piense en decltype() como ” dame una expresión válida de tipo T “. Por supuesto, su uso está destinado a la resolución de sobrecargas, la determinación de tipos, etc .; ya que su propósito es devolver una expresión válida (en el sentido sintáctico), no devolver un valor. Eso se refleja en el hecho de que std::declval() no está definido en absoluto, solo se declara.
Si se definió, tenemos el problema inicial nuevamente (tenemos que construir un valor para un tipo T arbitrario, y eso no es posible).