Tengo algunas preguntas sobre este programa:
#include <iostream>
#include <type_traits>
#include <functional>
using namespace std;
template <typename T> void foo ( T x )
{
auto r=ref(x);
cout<<boolalpha;
cout<<is_same<T&,decltype(r)>::value;
}
int main()
{
int x=5;
foo (x);
return 0;
}
La salida es:
false
Quiero saber, si std::refno devuelve la referencia de un objeto, ¿qué hace? Básicamente, ¿cuál es la diferencia entre:
T x;
auto r = ref(x);
y
T x;
T &y = x;
Además, quiero saber por qué existe esta diferencia. ¿Por qué necesitamos std::refo std::reference_wrappercuando tenemos referencias (es decir T&)?

x = y;en ambos casos?Respuestas:
Well
refconstruye un objeto delreference_wrappertipo apropiado para contener una referencia a un objeto. Lo que significa que cuando aplicas:auto r = ref(x);Esto devuelve a
reference_wrappery no una referencia directa ax(ieT&). En cambio, estoreference_wrapper(es decirr) se mantieneT&.Una
reference_wrapperes muy útil cuando se desea emular unareferencede un objeto que se puede copiar (que es a la vez -construible copia y copiar asignable ).En C ++, una vez que crea una referencia (digamos
y) a un objeto (digamosx), entoncesyyxcomparte la misma dirección base . Además,yno puede referirse a ningún otro objeto. Además, no puede crear una matriz de referencias, es decir, un código como este arrojará un error:#include <iostream> using namespace std; int main() { int x=5, y=7, z=8; int& arr[] {x,y,z}; // error: declaration of 'arr' as array of references return 0; }Sin embargo, esto es legal:
#include <iostream> #include <functional> // for reference_wrapper using namespace std; int main() { int x=5, y=7, z=8; reference_wrapper<int> arr[] {x,y,z}; for (auto a: arr) cout << a << " "; return 0; } /* OUTPUT: 5 7 8 */Hablando de tu problema con
cout << is_same<T&,decltype(r)>::value;, la solución es:cout << is_same<T&,decltype(r.get())>::value; // will yield trueDéjame mostrarte un programa:
#include <iostream> #include <type_traits> #include <functional> using namespace std; int main() { cout << boolalpha; int x=5, y=7; reference_wrapper<int> r=x; // or auto r = ref(x); cout << is_same<int&, decltype(r.get())>::value << "\n"; cout << (&x==&r.get()) << "\n"; r=y; cout << (&y==&r.get()) << "\n"; r.get()=70; cout << y; return 0; } /* Ouput: true true true 70 */Mira aquí llegamos a saber tres cosas:
Un
reference_wrapperobjeto (aquír) se puede usar para crear una matriz de referencias que no era posible conT&.ren realidad actúa como una referencia real (vea cómor.get()=70cambió el valor dey).rno es lo mismo queT&peror.get()es. Esto significa que sermantiene,T&es decir, como sugiere su nombre, es un envoltorio alrededor de una referenciaT&.Espero que esta respuesta sea más que suficiente para explicar tus dudas.
fuente
reference_wrapperse puede reasignar a , pero no puede "contener referencia a más de un objeto". 2/3: punto justo sobre dónde.get()es apropiado, pero sin sufijorse puede usar de la misma manera queT&en los casos enrlos que la conversiónoperatorse puede invocar de manera inequívoca, por lo que no es necesario llamar.get()en muchos casos, incluidos varios en su código (que es difícil de leer por falta de espacios).reference_wrapperpuede contener una serie de referencias si no está seguro, puede probarlo usted mismo. Plus.get()se usa cuando desea cambiar el valor del objeto quereference_wrapperestá sosteniendo,r=70es decir, es ilegal, por lo que debe usarr.get()=70. Pruébelo usted mismo !!!!!!int a[4]{1, 2, 3, 4}; int (&b)[4] = a;? reference_wrapper no es especial aquí ya que el nativoT&sí funciona.wrapperpuede ir en un recipiente. Esto es útil, pero creo que la gente lo malinterpreta como más avanzado de lo que realmente es. Si quiero una serie de 'referencias', generalmente me salto al intermediariovector<Item *>, que es a lo que sewrapperreduce ... y espero que los puristas anti-punteros no me encuentren. Los casos de uso convincentes son diferentes y más complejos.std::reference_wrapperes reconocido por las instalaciones estándar para poder pasar objetos por referencia en contextos de paso por valor.Por ejemplo,
std::bindpuedestd::ref()incorporar a algo, transmitirlo por valor y descomprimirlo en una referencia más adelante.void print(int i) { std::cout << i << '\n'; } int main() { int i = 10; auto f1 = std::bind(print, i); auto f2 = std::bind(print, std::ref(i)); i = 20; f1(); f2(); }Este fragmento da como resultado:
10 20El valor de
ise ha almacenado (tomado por valor) enf1el punto en el que se inicializó, perof2ha mantenido unstd::reference_wrappervalor por valor y, por lo tanto, se comporta como si hubiera tomado un valorint&.fuente
std::ref(T)devuelve unstd::reference_wrapper. Es poco más que un puntero envuelto, pero la biblioteca lo reconoce como "¡Oye, se supone que debo ser una referencia! Por favor, conviérteme en uno una vez que hayas terminado de pasarme".Una referencia (
T&oT&&) es un elemento especial en el lenguaje C ++. Permite manipular un objeto por referencia y tiene casos de uso especiales en el lenguaje. Por ejemplo, no puede crear un contenedor estándar para contener referencias:vector<T&>está mal formado y genera un error de compilación.A,
std::reference_wrapperpor otro lado, es un objeto C ++ capaz de contener una referencia. Como tal, puede usarlo en contenedores estándar.std::refes una función estándar que devuelve unstd::reference_wrapperen su argumento. En la misma idea,std::crefvuelvestd::reference_wrappera una referencia constante.Una propiedad interesante de a
std::reference_wrapper, es que tiene unoperator T& () const noexcept;. Eso significa que incluso si es un objeto verdadero , se puede convertir automáticamente a la referencia que contiene. Entonces:operator T& () const noexcept;él, se puede usar en cualquier lugar donde pueda usar una referencia, ya que se convertirá automáticamente a ella.fuente
operator T& ()que otras 2 respuestas no mencionaron.