关于C#:此std :: ref行为是否合乎逻辑?

Is this std::ref behaviour logical?

考虑以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#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;
}

执行时,此代码输出

1
2
107
100

我希望第二个值是7而不是100。

我想念什么?


f2的一个小修改提供了线索:

1
2
3
4
5
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=)

它不给包装的引用赋值。

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

)执行加法。

因此观察到的行为是正确的。