C ++ std :: ref(T)和T&amp ;?之间的区别

时间:2015-10-20 15:41:25

标签: c++ reference ref

我对此计划有一些疑问:

#include <iostream>
#include <type_traits>
#include <functional>
using namespace std;
template <typename T> void foo ( T x )
{
    auto r=ref(x);
    cout<<boolalpha;
    cout<<is_same<T&,decltype(r)>::value;
}
int main()
{
    int x=5;
    foo (x);
    return 0;
}

输出结果为:

false

我想知道,如果std::ref没有返回对象的引用,那么它会做什么?基本上,有什么区别:

T x;
auto r = ref(x);

T x;
T &y = x;

另外,我想知道为什么存在这种差异?当我们有引用时(std::ref),为什么我们需要std::reference_wrapperT&

3 个答案:

答案 0 :(得分:58)

ref构造一个适当的reference_wrapper类型的对象来保存对象的引用。这意味着当您申请时:

auto r = ref(x);

这会返回reference_wrapper,而不是x的直接引用(即T&)。此reference_wrapper(即r)代替T&

当你想模仿一个可以复制的对象的reference_wrapper时,reference非常有用(它是 copy-constructible copy-分配)。

在C ++中,一旦您为对象创建引用(比如说y)(比如说x),那么yx会共享相同的基础解决。此外,y不能引用任何其他对象。此外,您无法创建引用数组,即这样的代码将引发错误:

#include <iostream>
using namespace std;

int main()
{
    int x=5, y=7, z=8;
    int& arr[] {x,y,z};    // error: declaration of 'arr' as array of references
    return 0;
}

但这是合法的:

#include <iostream>
#include <functional>  // for reference_wrapper
using namespace std;

int main()
{
    int x=5, y=7, z=8;
    reference_wrapper<int> arr[] {x,y,z};
    for (auto a: arr)
        cout << a << " ";
    return 0;
}
/* OUTPUT:
5 7 8
*/

使用cout << is_same<T&,decltype(r)>::value;谈论您的问题,解决方案是:

cout << is_same<T&,decltype(r.get())>::value;  // will yield true

让我告诉你一个程序:

#include <iostream>
#include <type_traits>
#include <functional>
using namespace std;

int main()
{
    cout << boolalpha;
    int x=5, y=7;
    reference_wrapper<int> r=x;   // or auto r = ref(x);
    cout << is_same<int&, decltype(r.get())>::value << "\n";
    cout << (&x==&r.get()) << "\n";
    r=y;
    cout << (&y==&r.get()) << "\n";
    r.get()=70;
    cout << y;
    return 0;
}
/* Ouput:
true
true
true
70
*/

看到这里我们了解三件事:

  1. reference_wrapper对象(此处为r)可用于创建引用数组,这是T&无法实现的。

  2. r实际上就像一个真正的参考(请参阅r.get()=70如何更改y的值)。

  3. rT&不同,但r.get()不同。这意味着r拥有T&,即顾名思义是围绕参考 T&的包装。

  4. 我希望这个答案足以解释你的疑虑。

答案 1 :(得分:39)

标准工具可以识别

std::reference_wrapper,以便能够在按值传递的上下文中通过引用传递对象。

例如,std::bind可以将std::ref()接收到某个内容,按值传输,然后将其解压缩回参考中。

void print(int i) {
    std::cout << i << '\n';
}

int main() {
    int i = 10;

    auto f1 = std::bind(print, i);
    auto f2 = std::bind(print, std::ref(i));

    i = 20;

    f1();
    f2();
}

此代码段输出:

10
20

i的值已在初始化时存储(按值)到f1,但f2按值保存std::reference_wrapper,并且因此表现得像int&

答案 2 :(得分:23)

引用(T&T&&)是C ++语言中的特殊元素。它允许通过引用操作对象,并且在该语言中具有特殊用例。例如,您无法创建标准容器来保存引用:vector<T&>生成错误并生成编译错误。

另一方面,std::reference_wrapper是能够保存引用的C ++对象。因此,您可以在标准容器中使用它。

std::ref是一个标准函数,在其参数上返回std::reference_wrapper。同样的想法,std::crefstd::reference_wrapper返回给const引用。

std::reference_wrapper的一个有趣属性是,它有一个operator T& () const noexcept;。这意味着即使它是一个真正的对象,它也可以自动转换为它所持有的引用。所以:

  • 因为它是一个可复制的对象,它可以在容器中使用,也可以在不允许引用的其他情况下使用
  • 感谢operator T& () const noexcept;,它可以在任何可以使用引用的地方使用,因为它会自动转换为它。