问题
Consider this code:
#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;
}
When executed, this code outputs
107
100
I would have expected the second value to be 7 rather than 100.
What am I missing?
回答1:
A small modification to f2 provides the clue:
template<class T>
void f2(T arg)
{
arg.get() = xx;
}
This now does what you expect.
This has happened because std::ref returns a std::reference_wrapper<> object. The assignment operator of which rebinds the wrapper.
(see http://en.cppreference.com/w/cpp/utility/functional/reference_wrapper/operator%3D)
It does not make an assignment to the wrapped reference.
In the f1 case, all is working as you expected because a std::reference_wrapper<T> provides a conversion operator to T&, which will bind to the implicit right hand side of ints implicit operator+.
回答2:
reference_wrapper has operator = and a non explicit constructor, see documentation.
So, even if it is surprising, it is the normal behaviour:
f2 rebinds the local reference_wrapper to xx.
回答3:
arg = xx;
Local arg now refers to (read as binds with) xx. (And no more refers to j)
arg += xx;
Implicit operator T& () is applied to match the argument of operator += and hence addition is performed on referred object i.e. j.
So the observed behaviour is correct.
来源:https://stackoverflow.com/questions/37101301/is-this-stdref-behaviour-logical