std::reference_wrapper
è utile in combinazione con i modelli. Avvolge un oggetto memorizzando un puntatore ad esso, consentendo la riassegnazione e la copia mentre imita la sua solita semantica. Indica inoltre ad alcuni modelli di libreria di memorizzare i riferimenti invece degli oggetti.
Considera gli algoritmi nell'STL che copiano i funtori: puoi evitare quella copia semplicemente passando un wrapper di riferimento che si riferisce al funtore invece del funtore stesso:
unsigned arr[10];
std::mt19937 myEngine;
std::generate_n( arr, 10, std::ref(myEngine) ); // Modifies myEngine's state
Funziona perché ...
... reference_wrapper
s sovraccarico inoperator()
modo che possano essere chiamati proprio come gli oggetti funzione a cui si riferiscono:
std::ref(myEngine)() // Valid expression, modifies myEngines state
... (non) come i riferimenti ordinari, la copia (e l'assegnazione) reference_wrappers
assegna solo le punte.
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>
Copiare un wrapper di riferimento è praticamente equivalente a copiare un puntatore, il che è il più economico possibile. Tutte le chiamate di funzione inerenti al suo utilizzo (ad esempio quelle a operator()
) dovrebbero essere solo inline in quanto sono one-line.
reference_wrapper
vengono creati tramite std::ref
estd::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>
L'argomento template specifica il tipo e la qualifica cv dell'oggetto a cui si fa riferimento; r2
si riferisce a const int
e fornirà solo un riferimento a const int
. Chiamate a wrapper di riferimento con const
funtori in essi chiameranno solo const
funzioni membro operator()
s.
Gli inizializzatori Rvalue non sono consentiti, poiché consentirli farebbe più male che bene. Poiché rvalues verrebbe spostato comunque (e con l' elisione della copia garantita anche in parte evitata), non miglioriamo la semantica; possiamo però introdurre puntatori pendenti, poiché un wrapper di riferimento non prolunga la durata della punta.
Interazione con la libreria
Come accennato in precedenza, si può istruire make_tuple
a memorizzare un riferimento nel risultato tuple
passando l'argomento corrispondente tramite a 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&>
Nota che questo differisce leggermente da forward_as_tuple
: Qui, rvalues come argomenti non sono consentiti.
std::bind
mostra lo stesso comportamento: non copia l'argomento ma memorizza un riferimento se è un file reference_wrapper
. Utile se quell'argomento (o il funtore!) Non deve essere copiato ma rimane nell'ambito mentre bind
viene utilizzato il -functor.
Differenza dai normali puntatori
Non esiste un livello aggiuntivo di riferimento indiretto sintattico. I puntatori devono essere dereferenziati per ottenere un valore per l'oggetto a cui si riferiscono; reference_wrapper
hanno un operatore di conversione implicito e possono essere chiamati come l'oggetto che racchiudono.
int i;
int& ref = std::ref(i); // Okay
reference_wrapper
s, a differenza dei puntatori, non hanno uno stato nullo. Devono essere inizializzati con un riferimento o un altroreference_wrapper
.
std::reference_wrapper<int> r; // Invalid
Una somiglianza è la semantica della copia superficiale: i puntatori e le reference_wrapper
s possono essere riassegnati.
.
con invece di->