这种 std::ref 行为合乎逻辑吗?

Is this std::ref behaviour logical?

考虑这段代码:

#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 returns 一个 std::reference_wrapper<> 对象。 重新绑定 包装器的赋值运算符。 (参见 http://en.cppreference.com/w/cpp/utility/functional/reference_wrapper/operator%3D

它不对包装引用进行赋值。

f1 的情况下,一切都按您预期的那样工作,因为 std::reference_wrapper<T> 提供了一个到 T& 的转换运算符,它将绑定到 [= 的隐式右侧17=]s 隐式 operator+.

reference_wrapperoperator = 和一个非显式构造函数,请参阅 documentation

所以,即使令人惊讶,这也是正常行为:

f2 将本地 reference_wrapper 重新绑定到 xx

arg = xx;

本地 arg 现在指的是(读作绑定)xx。 (且不再指j

arg += xx;

隐式 operator T& () 用于匹配 operator += 的参数,因此对引用对象执行加法,即 j.

所以观察到的行为是正确的。