std::reference_wrapper
jest 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_wrapper
S 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_wrappers
po 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_wrapper
s są tworzone przez std::ref
istd::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; r2
odnosi się do a const int
i zwróci tylko odniesienie do const int
. Wywołania opakowań referencyjnych z const
funktorami będą wywoływać tylko const
funkcje 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_tuple
aby 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::bind
pokazuje 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 bind
uż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_wrapper
s mają niejawny operator konwersji i mogą być wywoływane jak zawijany obiekt.
int i;
int& ref = std::ref(i); // Okay
reference_wrapper
s, 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_wrapper
s można ponownie przypisać.
.
zamiast->