std::reference_wrapperполезно в сочетании с шаблонами. Он обертывает объект, сохраняя указатель на него, позволяя переназначать и копировать, имитируя его обычную семантику. Он также указывает некоторым шаблонам библиотеки хранить ссылки вместо объектов.
Рассмотрим алгоритмы в STL, которые копируют функторы: вы можете избежать этой копии, просто передав ссылочную оболочку, ссылающуюся на функтор, а не на сам функтор:
unsigned arr[10];
std::mt19937 myEngine;
std::generate_n( arr, 10, std::ref(myEngine) ); // Modifies myEngine's state
Это работает, потому что…
… reference_wrapperS перегрузка,operator() чтобы их можно было вызывать точно так же, как объекты функций, на которые они ссылаются:
std::ref(myEngine)() // Valid expression, modifies myEngines state
… (Не) как обычные ссылки, копирование (и присвоение) reference_wrappersпросто присваивает указатель.
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>
Копирование ссылочной оболочки практически эквивалентно копированию указателя, которое настолько дешево, насколько это возможно. Все вызовы функций, присущие его использованию (например, те, которые используются operator()), должны быть просто встроены, поскольку они являются однострочными.
reference_wrappers создаются через std::refиstd::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>
Аргумент шаблона определяет тип и квалификацию объекта, на который имеется ссылка; r2ссылается на a const intи дает только ссылку на const int. Вызовы ссылочных оболочек с constфункторами в них будут вызывать только constфункции-члены operator().
Инициализаторы Rvalue запрещены, поскольку их разрешение принесет больше вреда, чем пользы. Поскольку rvalues все равно будут перемещены (и с гарантированным исключением копирования, даже если этого частично избежать), мы не улучшаем семантику; мы можем ввести висячие указатели, поскольку обертка ссылок не продлевает время жизни указателя.
Библиотечное взаимодействие
Как упоминалось ранее, можно make_tupleуказать сохранить ссылку в результате tuple, передав соответствующий аргумент через 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&>
Обратите внимание, что это немного отличается от forward_as_tuple: Здесь rvalues в качестве аргументов не допускаются.
std::bindпоказывает то же поведение: он не копирует аргумент, но сохраняет ссылку, если это reference_wrapper. Полезно, если этот аргумент (или функтор!) Не нужно копировать, но остается в области видимости, пока используется bind-функтор.
Отличие от обычных указателей
Дополнительного уровня синтаксической косвенности нет. Указатели должны быть разыменованы, чтобы получить l-значение для объекта, на который они ссылаются; reference_wrappers имеют неявный оператор преобразования и могут вызываться как объект, который они обертывают.
int i;
int& ref = std::ref(i); // Okay
reference_wrappers, в отличие от указателей, не имеет нулевого состояния. Они должны быть инициализированы ссылкой или другойreference_wrapper .
std::reference_wrapper<int> r; // Invalid
Сходство reference_wrapperзаключается в семантике неглубокого копирования: указатели и s можно переназначать.
.вместо->