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 eltype
typedef del miembro nombraráT&&
; de lo contrario,type
nombreT
[ Nota: esta regla refleja la semántica del colapso de referencia (8.3.2). Por ejemplo, cuando un tipoT
nombra un tipoT1&
, el tipoadd_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 tipoT
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óndeclval<T>()
es un lvalue si y solo siT
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.