std::reference_wrapperjest przydatna w połączeniu z szablonami. Zawija obiekt, przechowując do niego wskaźnik, umożliwiając ponowne przypisanie i kopiowanie, naśladując jego zwykłą semantykę. Nakazuje również niektórym szablonom bibliotek przechowywanie odniesień zamiast obiektów.
Rozważmy algorytmy w STL, które kopiują funktory: Możesz uniknąć tej kopii, przekazując po prostu opakowanie referencyjne odnoszące się do funktora zamiast do samego funktora:
unsigned arr[10];
std::mt19937 myEngine;
std::generate_n( arr, 10, std::ref(myEngine) ); // Modifies myEngine's state
To działa, ponieważ…
… reference_wrapperS przeciążenie,operator() więc można je wywołać tak jak obiekty funkcji, do których się odnoszą:
std::ref(myEngine)() // Valid expression, modifies myEngines state
… (Nie) jak zwykłe odniesienia, kopiowanie (i przypisywanie) reference_wrapperspo prostu przypisuje punkt.
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>
Kopiowanie opakowania referencyjnego jest praktycznie równoważne kopiowaniu wskaźnika, które jest tak tanie, jak to tylko możliwe. Wszystkie wywołania funkcji nieodłącznie związane z jej używaniem (np. Te do operator()) powinny być po prostu wstawiane, ponieważ są jednowierszowe.
reference_wrappers są tworzone przez std::refistd::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>
Argument szablonu określa typ i kwalifikację cv obiektu, do którego się odwołuje; r2odnosi się do a const inti zwróci tylko odniesienie do const int. Wywołania opakowań referencyjnych z constfunktorami będą wywoływać tylko constfunkcje operator()składowe s.
Inicjatory Rvalue są niedozwolone, ponieważ pozwolenie im przyniosłoby więcej szkody niż pożytku. Ponieważ rvalues i tak zostałyby przeniesione (i przy gwarantowanej eliminacji kopiowania, nawet jeśli jest to częściowo unikane), nie poprawiamy semantyki; możemy jednak wprowadzić wiszące wskaźniki, ponieważ opakowanie odniesienia nie przedłuża jego życia.
Interakcja biblioteki
Jak wspomniano wcześniej, można poinstruować, make_tupleaby zapisać odwołanie w wyniku tuple, przekazując odpowiedni argument przez 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&>
Zauważ, że to nieco różni się od forward_as_tuple: Tutaj rwartości jako argumenty nie są dozwolone.
std::bindpokazuje to samo zachowanie: nie skopiuje argumentu, ale zapisze odniesienie, jeśli jest to plik reference_wrapper. Przydatne, jeśli ten argument (lub funktor!) Nie musi być kopiowany, ale pozostaje w zakresie, gdy bindużywany jest -functor.
Różnica w stosunku do zwykłych wskaźników
Nie ma dodatkowego poziomu pośrednictwa syntaktycznego. Wskaźniki muszą zostać wyłuskane, aby uzyskać lwartość dla obiektu, do którego się odnoszą; reference_wrappers mają niejawny operator konwersji i mogą być wywoływane jak zawijany obiekt.
int i;
int& ref = std::ref(i); // Okay
reference_wrappers, w przeciwieństwie do wskaźników, nie mają stanu zerowego. Muszą zostać zainicjowane za pomocą odwołania lub innegoreference_wrapper .
std::reference_wrapper<int> r; // Invalid
Podobieństwo występuje w semantyce płytkiej kopii: wskaźniki i reference_wrappers można ponownie przypisać.
.zamiast->