std::reference_wrapperes ú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_wrappers 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_wrapperssimplemente 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_wrapperLos mensajes de correo electrónico se crean mediante std::refystd::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; r2se refiere a const intay solo dará una referencia a const int. Las llamadas a envoltorios de referencia con constfunctores en ellos solo llamarán a constfunciones 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_tuplepara almacenar una referencia en el resultado tuplepasando 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::bindmuestra 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 bindse 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_wrappers 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_wrappers, 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_wrappers pueden reasignarse.
.en lugar de->