C+ std::ref(T)和t&?

时间:2021-07-25 18:55:54

I have some questions regarding this program:

关于这个项目,我有一些问题:

#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;
}

The output is:

的输出是:

false

I want to know, if std::ref doesn't return the reference of an object, then what does it do? Basically, what is the difference between:

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

T x;
auto r = ref(x);

and

T x;
T &y = x;

Also, I want to know why does this difference exist? Why do we need std::ref or std::reference_wrapper when we have references (i.e. T&)?

另外,我想知道为什么会存在这种差异?为什么我们需要std::ref或std::reference_wrapper当我们有了引用(即T&)?

3 个解决方案

#1


36  

Well ref constructs an object of the appropriate reference_wrapper type to hold a reference to an object. Which means when you apply :-

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

auto r = ref(x);

This return a reference_wrapper & not a direct reference to x (ie T&). This reference_wrapper (ie r) instead holds T&.

这返回一个reference_wrapper,而不是x的直接引用(ie &)。这个reference_wrapper (ie r)代替了&。

A reference_wrapper is very useful when you want to emulate a reference of an object which can be copied (it is both copy-constructible and copy-assignable).

当您希望模拟可复制对象的引用时,reference_wrapper是非常有用的(它既是可复制的,也是可复制的)。

In C++, once you create a reference (say y) to an object (say x), then y & x share the same base address. Furthermore, y cannot refer to any other object. Also you cannot create an array of references ie a code like this will throw an error :-

在c++中,一旦创建了一个对象(比如y)到一个对象(比如x),那么y & x就会共享相同的基本地址。此外,y不能引用任何其他对象。你也不能创建一个引用数组ie这样的代码会抛出一个错误:-

#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;
}

However this is legal :-

但是这是合法的

#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
*/

Talking about your problem with cout<<is_same<T&,decltype(r)>::value;, the solution is :-

关于cout< is_same ::value &,decltype(r)>

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

Let me show you a program :-

让我给你看一个节目:-

#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
*/

See here we get to know three things :-

看这里,我们知道了三件事:-

  1. reference_wrapper object (here r) can be used to create an array of references which was not possible with T&.

    reference_wrapper对象(这里是r)可以用来创建一个不可能使用t&i的引用数组。

  2. r actually acts like a real reference ( see how r.get()=70 changed the value of y).

    r实际上就像一个真正的引用(参见r.get()=70如何改变y的值)。

  3. r is not same as T& but r.get() is. This means that r holds T& ie as it's name suggests is a wrapper around reference T&.

    r与t&but r.get()不同。这意味着r保存了t&ie,因为它的名字表明它是引用t&e的包装。

I hope this answer is more than enough to explain your doubts.

我希望这个答案足以解释你的疑问。

#2


32  

std::reference_wrapper is recognized by standard facilities to be able to pass objects by reference in pass-by-value contexts.

:reference_wrapper是被标准设施认可的,它能够通过引用在按值传递上下文中传递对象。

For example, std::bind can take in the std::ref() to something, transmit it by value, and unpacks it back into a reference later on.

例如,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();
}

This snippet outputs :

这段代码输出:

10
20

The value of i has been stored (taken by value) into f1 at the point it was initialized, but f2 has kept an std::reference_wrapper by value, and thus behaves like it took in an int&.

i的值在初始化时被存储到f1中,但是f2保留了一个std::reference_wrapper的值,因此它的行为就像在int&中一样。

#3


16  

A reference (T& or T&&) is a special element in C++ language. It allows to manipulate an object by reference and has special use cases in the language. For example, you cannot create a standard container to hold references: vector<T&> is ill formed and generates a compilation error.

引用(t&or &)是c++语言中的一个特殊元素。它允许通过引用操作对象,并且在语言中有特殊的用例。例如,您不能创建一个标准容器来保存引用:vector< t&>是不成立的,并生成一个编译错误。

A std::reference_wrapper on the other hand is a C++ object able to hold a reference. As such, you can use it in standard containers.

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

std::ref is a standard function that returns a std::reference_wrapper on its argument. In the same idea, std::cref returns std::reference_wrapper to a const reference.

ref是一个标准函数,在其参数上返回std::reference_wrapper。同样,std::cref将std::reference_wrapper返回到const引用。

One interesting property of a std::reference_wrapper, is that it has an operator T& () const noexcept;. That means that even if it is a true object, it can be automatically converted to the reference that it is holding. So:

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

  • as it is a copy assignable object, it can be used in containers or in other cases where references are not allowed
  • 由于它是一个可分配的对象,可以在容器中使用,也可以在不允许引用的情况下使用。
  • thanks to its operator T& () const noexcept;, it can be used anywhere you could use a reference, because it will be automatically converted to it.
  • 由于它的操作符t&() const noexcept,它可以在任何您可以使用引用的地方使用,因为它将自动转换为引用。

#1


36  

Well ref constructs an object of the appropriate reference_wrapper type to hold a reference to an object. Which means when you apply :-

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

auto r = ref(x);

This return a reference_wrapper & not a direct reference to x (ie T&). This reference_wrapper (ie r) instead holds T&.

这返回一个reference_wrapper,而不是x的直接引用(ie &)。这个reference_wrapper (ie r)代替了&。

A reference_wrapper is very useful when you want to emulate a reference of an object which can be copied (it is both copy-constructible and copy-assignable).

当您希望模拟可复制对象的引用时,reference_wrapper是非常有用的(它既是可复制的,也是可复制的)。

In C++, once you create a reference (say y) to an object (say x), then y & x share the same base address. Furthermore, y cannot refer to any other object. Also you cannot create an array of references ie a code like this will throw an error :-

在c++中,一旦创建了一个对象(比如y)到一个对象(比如x),那么y & x就会共享相同的基本地址。此外,y不能引用任何其他对象。你也不能创建一个引用数组ie这样的代码会抛出一个错误:-

#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;
}

However this is legal :-

但是这是合法的

#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
*/

Talking about your problem with cout<<is_same<T&,decltype(r)>::value;, the solution is :-

关于cout< is_same ::value &,decltype(r)>

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

Let me show you a program :-

让我给你看一个节目:-

#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
*/

See here we get to know three things :-

看这里,我们知道了三件事:-

  1. reference_wrapper object (here r) can be used to create an array of references which was not possible with T&.

    reference_wrapper对象(这里是r)可以用来创建一个不可能使用t&i的引用数组。

  2. r actually acts like a real reference ( see how r.get()=70 changed the value of y).

    r实际上就像一个真正的引用(参见r.get()=70如何改变y的值)。

  3. r is not same as T& but r.get() is. This means that r holds T& ie as it's name suggests is a wrapper around reference T&.

    r与t&but r.get()不同。这意味着r保存了t&ie,因为它的名字表明它是引用t&e的包装。

I hope this answer is more than enough to explain your doubts.

我希望这个答案足以解释你的疑问。

#2


32  

std::reference_wrapper is recognized by standard facilities to be able to pass objects by reference in pass-by-value contexts.

:reference_wrapper是被标准设施认可的,它能够通过引用在按值传递上下文中传递对象。

For example, std::bind can take in the std::ref() to something, transmit it by value, and unpacks it back into a reference later on.

例如,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();
}

This snippet outputs :

这段代码输出:

10
20

The value of i has been stored (taken by value) into f1 at the point it was initialized, but f2 has kept an std::reference_wrapper by value, and thus behaves like it took in an int&.

i的值在初始化时被存储到f1中,但是f2保留了一个std::reference_wrapper的值,因此它的行为就像在int&中一样。

#3


16  

A reference (T& or T&&) is a special element in C++ language. It allows to manipulate an object by reference and has special use cases in the language. For example, you cannot create a standard container to hold references: vector<T&> is ill formed and generates a compilation error.

引用(t&or &)是c++语言中的一个特殊元素。它允许通过引用操作对象,并且在语言中有特殊的用例。例如,您不能创建一个标准容器来保存引用:vector< t&>是不成立的,并生成一个编译错误。

A std::reference_wrapper on the other hand is a C++ object able to hold a reference. As such, you can use it in standard containers.

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

std::ref is a standard function that returns a std::reference_wrapper on its argument. In the same idea, std::cref returns std::reference_wrapper to a const reference.

ref是一个标准函数,在其参数上返回std::reference_wrapper。同样,std::cref将std::reference_wrapper返回到const引用。

One interesting property of a std::reference_wrapper, is that it has an operator T& () const noexcept;. That means that even if it is a true object, it can be automatically converted to the reference that it is holding. So:

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

  • as it is a copy assignable object, it can be used in containers or in other cases where references are not allowed
  • 由于它是一个可分配的对象,可以在容器中使用,也可以在不允许引用的情况下使用。
  • thanks to its operator T& () const noexcept;, it can be used anywhere you could use a reference, because it will be automatically converted to it.
  • 由于它的操作符t&() const noexcept,它可以在任何您可以使用引用的地方使用,因为它将自动转换为引用。