std::reference_wrapper
es útil en combinación con plantillas. Envuelve un objeto almacenando un puntero hacia él, lo que permite la reasignación y la copia mientras imita su semántica habitual. También indica a ciertas plantillas de biblioteca que almacenen referencias en lugar de objetos.
Considere los algoritmos en el STL que copian functores: puede evitar esa copia simplemente pasando un contenedor de referencia que se refiera al functor en lugar del functor en sí:
unsigned arr[10];
std::mt19937 myEngine;
std::generate_n( arr, 10, std::ref(myEngine) ); // Modifies myEngine's state
Esto funciona porque ...
... reference_wrapper
s sobrecargaoperator()
para que se puedan llamar como los objetos de función a los que se refieren:
std::ref(myEngine)() // Valid expression, modifies myEngines state
… (Des) me gustan las referencias ordinarias, copiar (y asignar) reference_wrappers
simplemente asigna el puntero.
int i, j;
auto r = std::ref(i); // r refers to i
r = std::ref(j); // Okay; r refers to j
r = std::cref(j); // Error: Cannot bind reference_wrapper<int> to <const int>
Copiar un contenedor de referencia es prácticamente equivalente a copiar un puntero, que es lo más económico posible. Todas las llamadas a funciones inherentes a su uso (por ejemplo, las que operator()
deben) deben estar en línea, ya que son una línea.
reference_wrapper
Los mensajes de correo electrónico se crean mediante std::ref
ystd::cref
:
int i;
auto r = std::ref(i); // r is of type std::reference_wrapper<int>
auto r2 = std::cref(i); // r is of type std::reference_wrapper<const int>
El argumento de plantilla especifica el tipo y la calificación cv del objeto al que se hace referencia; r2
se refiere a const int
ay solo dará una referencia a const int
. Las llamadas a envoltorios de referencia con const
functores en ellos solo llamarán a const
funciones miembro operator()
.
Los inicializadores Rvalue no están permitidos, ya que permitirlos haría más daño que bien. Dado que los rvalues se moverían de todos modos (y con la elisión de copia garantizada incluso eso se evita en parte), no mejoramos la semántica; Sin embargo, podemos introducir punteros colgantes, ya que una envoltura de referencia no extiende la vida útil del puntero.
Interacción con la biblioteca
Como se mencionó anteriormente, uno puede instruir make_tuple
para almacenar una referencia en el resultado tuple
pasando el argumento correspondiente a través de un reference_wrapper
:
int i;
auto t1 = std::make_tuple(i); // Copies i. Type of t1 is tuple<int>
auto t2 = std::make_tuple(std::ref(i)); // Saves a reference to i.
// Type of t2 is tuple<int&>
Tenga en cuenta que esto difiere ligeramente de forward_as_tuple
: Aquí, no se permiten valores r como argumentos.
std::bind
muestra el mismo comportamiento: no copiará el argumento, pero almacenará una referencia si es un reference_wrapper
. Útil si ese argumento (¡o el functor!) No necesita copiarse pero permanece dentro del alcance mientras bind
se usa el -functor.
Diferencia de punteros ordinarios
No hay un nivel adicional de indirección sintáctica. Los punteros deben desreferenciarse para obtener un valor l del objeto al que se refieren; reference_wrapper
s tienen un operador de conversión implícito y se pueden llamar como el objeto que envuelven.
int i;
int& ref = std::ref(i); // Okay
reference_wrapper
s, a diferencia de los punteros, no tienen un estado nulo. Deben inicializarse con una referencia u otrareference_wrapper
.
std::reference_wrapper<int> r; // Invalid
Una similitud es la semántica de copia superficial: los punteros y reference_wrapper
s pueden reasignarse.
.
en lugar de->