versiones existentes dev compiler c++ c++11

existentes - dev c++



¿Por qué se especifica ''declval'' en términos de ''add_rvalue_reference<T>:: type'' y no ''T &&''? (3)

§20.2.4 [declval]

template <class T> typename add_rvalue_reference<T>::type declval() noexcept; // as unevaluated operand

¿Por qué usar add_rvalue_reference aquí?

De §20.9.7.2 [meta.trans.ref] en add_rvalue_reference :

Si T nombra un tipo de objeto o función, entonces el type typedef del miembro nombrará T&& ; de lo contrario, type nombre T [ Nota: esta regla refleja la semántica del colapso de referencia (8.3.2). Por ejemplo, cuando un tipo T nombra un tipo T1& , el tipo add_rvalue_reference<T>::type no es una referencia de rvalue. "Nota final "

Dado que add_rvalue_reference está destinado a reflejar el colapso de las referencias de todos modos, ¿por qué no usar T&& como el siguiente?

template<class T> T&& declval();

¿Qué puede salir mal? ¿Cuáles son exactamente las diferencias entre las dos versiones?


La diferencia es que add_rvalue_reference<> solo agrega realmente la parte && si T es un tipo de objeto o función. Si T no es un tipo de objeto o función (por ejemplo, void ), no desea agregar && .

Vea este ejemplo en Ideone .
Esta página web de la implementación de Boost explica:

El rol de la plantilla de función declval() es una transformación de un tipo T en un valor sin usar o evaluar esta función. Se supone que el nombre dirige la atención del lector al hecho de que la expresión declval<T>() es un lvalue si y solo si T es un lvalue-reference, de lo contrario es un rvalue. Para extender el dominio de esta función podemos mejorar un poco su declaración a

template<class T> typename std::add_rvalue_reference<T>::type declval(); // not used

lo que asegura que también podemos usar cv void como parámetro de plantilla.


No sé si esta es la razón real, pero add_rvalue_reference tiene un comportamiento diferente para el void .

add_rvalue_reference<void>::type es simplemente void .

void&& es un error.


Varias definiciones dependen de que declval dé resultados razonables para el void calificado por declval . Un ejemplo es is_assignable :

template <class T, class U> struct is_assignable;

La expresión declval<T>() = declval<U>() está bien formada cuando se trata como un operando sin evaluar ...

La intención es que "bien formado" se refiere a la buena formación de la expresión de asignación, y no a si declval<T> está bien formado. Es decir, queremos preocuparnos por una sola cosa a la vez.