Рассмотрим этот код:
#include <iostream>
#include <functional>
int xx = 7;
template<class T>
void f1(T arg)
{
arg += xx;
}
template<class T>
void f2(T arg)
{
arg = xx;
}
int main()
{
int j;
j=100;
f1(std::ref(j));
std::cout << j << std::endl;
j=100;
f2(std::ref(j));
std::cout << j << std::endl;
}
При выполнении этот код выводит
107
100
Я бы ожидал, что второе значение будет 7, а не 100.
Что мне не хватает?
Небольшая модификация f2
предоставляет ключ:
template<class T>
void f2(T arg)
{
arg.get() = xx;
}
Это теперь делает то, что вы ожидаете.
Это произошло потому, что std::ref
возвращает std::reference_wrapper<>
объект. Оператор присваивания которого повторное связывание обертка.
(увидеть http://en.cppreference.com/w/cpp/utility/functional/reference_wrapper/operator%3D)
Он не присваивает завернутую ссылку.
в f1
случай, все работает так, как вы ожидали, потому что std::reference_wrapper<T>
предоставляет оператор преобразования в T&
, который будет привязан к неявной правой части int
с неявным operator+
,
reference_wrapper
имеет operator =
и неявный конструктор, см. документация.
Итак, даже если это удивительно, это нормальное поведение:
f2
связывает локальный reference_wrapper с xx
,
arg = xx;
Местный arg
теперь относится к (читается как связывает с) xx
, (И больше не относится к j
)
arg += xx;
неявный operator T& ()
применяется в соответствии с аргументом operator +=
и, следовательно, добавление выполняется для упомянутого объекта, т.е. j
,
Таким образом, наблюдаемое поведение является правильным.