pointer pass documentacion cplusplus c++ reference ref

pass - C++ Diferencia entre std:: ref(T) y T &?



stl c++ reference (3)

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; }

El resultado es:

false

Quiero saber, si std::ref no 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::ref o std::reference_wrapper cuando tenemos referencias (es decir, T& )?


Una referencia ( T& o T&& ) es un elemento especial en 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: el vector<T&> está mal formado y genera un error de compilación.

Un std::reference_wrapper por otro lado es un objeto C ++ capaz de contener una referencia. Como tal, puede usarlo en contenedores estándar.

std::ref es una función estándar que devuelve un std::reference_wrapper en su argumento. En la misma idea, std::cref devuelve std::reference_wrapper a una referencia constante.

Una propiedad interesante de un std::reference_wrapper , es que tiene un operator T& () const noexcept; . Eso significa que, incluso si se trata de un objeto verdadero , se puede convertir automáticamente a la referencia que contiene. Asi que:

  • Como es un objeto asignable de copia, se puede usar en contenedores o en otros casos donde no se permiten referencias
  • gracias a su operator T& () const noexcept; , puede usarse en cualquier lugar donde pueda usar una referencia, ya que se convertirá automáticamente en ella.

Well ref construye un objeto del tipo reference_wrapper apropiado para contener una referencia a un objeto. Lo que significa cuando solicita:

auto r = ref(x);

Esto devuelve una reference_wrapper y no una referencia directa a x (es decir, T& ). Este reference_wrapper (es decir, r ) contiene T& .

reference_wrapper es muy útil cuando desea emular una reference de un objeto que se puede copiar (es a la vez construible y asignable ).

En C ++, una vez que crea una referencia (digamos y ) a un objeto (digamos x ), entonces y y x comparten la misma dirección base . Además, y no 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 sobre su problema con cout << is_same<T&,decltype(r)>::value; , la solucion es:

cout << is_same<T&,decltype(r.get())>::value; // will yield true

Dé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 conocer tres cosas:

  1. Un objeto reference_wrapper (aquí r ) se puede usar para crear una matriz de referencias que no era posible con T& .

  2. r realidad actúa como una referencia real (vea cómo r.get()=70 cambió el valor de y ).

  3. r no es lo mismo que T& pero r.get() es. Esto significa que r contiene T& ie, como su nombre lo indica, es una envoltura alrededor de una referencia T& .

Espero que esta respuesta sea más que suficiente para explicar tus dudas.


std::reference_wrapper es reconocido por las instalaciones estándar para poder pasar objetos por referencia en contextos de paso por valor.

Por ejemplo, std::bind puede std::ref() 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 genera:

10 20

El valor de i se ha almacenado (tomado por valor) en f1 en el punto en que se inicializó, pero f2 ha mantenido un std::reference_wrapper por valor y, por lo tanto, se comporta como si tomara un int& .