He aquí un ejemplo, posiblemente arquetípica, por eso que necesitamos remove_reference
, en la implementación de std::move
: El objetivo es devolver un tipo rvalue referencia, basado en el deducido tipo de argumento de la función.
Ejemplo: Foo x; move(x);
Aquí move(x)
debe devolver un tipo Foo&&
. Pero el argumento de move
es una expresión del tipo Foo&
. Entonces, ¿cómo puede la función move
deducir el tipo correcto?
El primer intento es utilizar la deducción argumento de plantilla ordinaria y utilizar un reparto:
template <typename T> T && move(??? x) { return static_cast<T&&>(x); }
Pero qué debe entrar ???
? Si decimos T x
, entonces T
se deduce como Foo&
; si decimos T & x
, luego T = Foo
, y si decimos T && x
, no coincidirá en absoluto. La segunda versión, T & x
, parece ser útil.
Pero entonces la función no funciona en rvalues, para empezar (por ejemplo move(Foo(...))
. En este caso, queremos T && x
modo que T = Foo
y T&& = Foo&&
lo deseas. Podríamos tener dos sobrecargas, pero tener múltiples sobrecargas no es deseable porque aumenta la complejidad innecesariamenteY finalmente, si alguien fuera a especificar el parámetro de la plantilla explícitamente como move<Foo&>(x)
, la función sería nunca funciona, porque cuando T = Foo&
, entonces también.
Así que en viene remove_reference
:
template <typename T>
typename std::remove_reference<T>::type && move(T && x)
{
return static_cast<typename std::remove_reference<T>::type &&>(x);
}
En primer lugar, la nueva referencia colapso reglas implican que es T
deduce como sea Foo&
o Foo&&
en los dos casos. Luego, remove_reference
quita la referencia y proporciona el tipo Foo
en cualquier caso, y al agregar &&
se obtiene el tipo de devolución Foo&&
deseado.
En un resumen muy simplificado: necesitamos remove_reference
porque (Foo&)&&
es Foo&
y no Foo&&
. Si alguna vez escribe un código de plantilla que necesita el tipo de base de un parámetro de plantilla que podría deducirse como U&
o U&&
, puede usar este modelo.
La respuesta es que necesitas aprender C++, y entonces deberías tener una idea de cómo hacer lo correcto. Lo siento si esto suena duro, pero una vez que tengas una comprensión más firme de las plantillas y la deducción de argumentos, podrás descifrar esto. Pero no tiene sentido saltar al fondo, * especialmente * mirando una implementación real de la biblioteca. Es como tratar de aprender griego antiguo desenterrando artefactos en Persia en lugar de leer un libro de texto. –
@KerrekSB: A veces es mucho más fácil aprender de un solo ejemplo bien explicado que de un libro de texto completo. Además, la mayoría de los libros de texto ni siquiera cubrirán este material, ya que se escribieron referencias rvalues en el idioma. Esta es una pregunta válida y bien formulada, que puedo imaginar que sea útil para mucha gente que está aprendiendo C++. – Mankarse
@KerrekSB Esto no es exactamente algo que pueda buscar. Incluso si sucediera a través de la regla que provocó que el ctor tuviera que hacer lo que hace, probablemente no la asociaría aquí sin ver ejemplos. En otra nota, ¿puedes dejar de disparar todas mis publicaciones? Claramente tienes un problema conmigo (no me importa por qué). – David