c++ c++11 decltype

c++ - ¿Por qué std:: declval agrega una referencia?



c++11 decltype (3)

El propósito de decltype() es tener una expresión que actúe como un valor válido de tipo T , para ponerlo como T en expresiones que esperan T s. El problema es que en C ++ un tipo T puede no ser copiable, o incluso no predecible-construible. Entonces, usar el T{} para ese propósito no funciona.

Lo que decltype() hace 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 tengamos una T válida a partir de una referencia rvalue de T , y se garantiza que podemos tener una referencia rvalue a cualquier tipo T Ese es el truco.

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

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

template< class T > typename std::add_rvalue_reference<T>::type declval() noexcept;

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

template< class T > T declval() noexcept;

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

El primer ejemplo histórico que encuentro es n2958 , que llama al value() la función value() pero siempre 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< typename t > t declprval() noexcept; class c { ~ c (); }; decltype ( declprval< c >() ) * p = nullptr; // OK


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

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

no compila De manera más general, 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<D>())) i2; // doesn''t compile. D must be a complete type

y hacerlo tiene poco beneficio ya que los valores x son prácticamente indistinguibles de los valores primos, excepto cuando se usa decltype en ellos, y normalmente 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 declaración de una función que devuelve una matriz por valor es un código no válido.

Sin embargo, puede devolver una matriz por referencia.