C++ Difference between std::ref(T) and T&?

后端 未结 3 1280
既然无缘
既然无缘 2021-01-29 22:30

I have some questions regarding this program:

#include 
#include 
#include 
using namespace std;
template &l         


        
相关标签:
3条回答
  • 2021-01-29 23:19

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

    auto r = ref(x);
    

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

    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).

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

    #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<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. A reference_wrapper object (here r) can be used to create an array of references which was not possible with T&.

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

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

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

    0 讨论(0)
  • 2021-01-29 23:30

    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.

    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.

    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.

    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:

    • 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.
    0 讨论(0)
  • 2021-01-29 23:34

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

    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.

    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&.

    0 讨论(0)
提交回复
热议问题