Это поведение std::ref логично?


рассмотрим этот код:

#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.

чего мне не хватает?

3 66

3 ответа:

небольшая модификация f2 предоставляет подсказку:

template<class T>
void f2(T arg)
{
    arg.get() = xx;
}

это сейчас делает то, что вы ожидаете.

это произошло потому, что std::ref возвращает a std::reference_wrapper<> "объект". Оператор присваивания которого привязывает фантик. (см. http://en.cppreference.com/w/cpp/utility/functional/reference_wrapper/operator%3D)

он не присваивает обернутую ссылку.

на f1 случае, все работает, как вы ожидали, потому что std::reference_wrapper<T> предоставляет оператор преобразования к T&, который будет привязан к неявной правой части ints implicit operator+.

reference_wrapper и operator = и не явный конструктор, см. документация.

так, даже если это удивительно, это нормальное поведение:

f2 привязывает к местной reference_wrapper xx.

arg = xx;

Local arg теперь относится к (читается как связывается с) xx. (И больше не относится к j)

arg += xx;

подразумевается operator T& () применяется для соответствия аргументу operator += и, следовательно, добавление выполняется на указанный объект т. е. j.

таким образом, наблюдаемое поведение является правильным.