• 创建一个对象或函数的引用,对象必须是 可复制(CopyConstructible)、可赋值(CopyAssignable) 的。

  • 它经常被用作在标准容器(如 std::vector )中存储引用的机制,而标准容器通常不能保存引用。

  • 辅助函数 std::refstd::cref 常用于生成 std::reference_wrapper 对象。

  • std::reference_wrapper 也用于按引用传递参数std::bindstd::thread 的构造函数。

  • 能隐式转换成 T&

  1. vector 中存储引用类型:

    #include <iostream>
    #include <list>
    #include <vector>
    #include <random>
    #include <functional>
    #include <algorithm>
    
    int main()
    {
        std::list<int> l(10);
        std::iota(l.begin(), l.end(), -4);  // 从 -4 开始,逐个 +1
    
        std::vector<std::reference_wrapper<int>> v(l.begin(), l.end());
        // 不能在 list 上用 shuffle (要求随机访问),但能在 vector 上使用它
        std::shuffle(v.begin(), v.end(), std::mt19937{std::random_device{}()});
    
        std::cout << "Contents of the list: ";
        for (int n : l) {
            std::cout << n << ' ';
        }
        std::cout << '\n';
    
        std::cout << "Contents of the list, as seen through a shuffled vector: ";
        for (int i : v) {
            std::cout << i << ' ';
        }
        std::cout << '\n';
    
        std::cout << "Doubling the values in the initial list...\n";
        for (int& i : l) {
            i *= 2;
        }
    
        std::cout << "Contents of the list, after doubling: ";
        for (int i : l) {
            std::cout << i << ' ';
        }
        std::cout << '\n';
    
        std::cout << "Contents of the list, as seen through a shuffled vector: ";
        for (int i : v) {
            std::cout << i << ' ';
        }
        std::cout << '\n';
    }
    

    输出:

    Contents of the list: -4 -3 -2 -1 0 1 2 3 4 5 
    Contents of the list, as seen through a shuffled vector: -3 2 0 3 -1 4 -4 1 5 -2 
    Doubling the values in the initial list...
    Contents of the list, after doubling: -8 -6 -4 -2 0 2 4 6 8 10 
    Contents of the list, as seen through a shuffled vector: -6 4 0 6 -2 8 -8 2 10 -4 
    
  2. 声明引用类型的数组

    int main()
    {
        int x = 5, y = 7, z = 8;
        std::reference_wrapper<int> arr[] {x, y, z};
        // int& arr[]{x,y,z}; // error: declaration of ‘arr’ as array of references
        for (auto a: arr)
            std::cout << a << " ";
        std::cout << std::endl;
        x = 50;
        std::cout << "-----------\n";
        for (auto a: arr)
            std::cout << a << " ";
    }    
    

    输出:

    5 7 8 
    -----------
    50 7 8 
    
  3. T&T 隐式转换

    void func(int& a, int b){
        cout << "in func: a = " << a << ", b = " << b << endl;
        a++;
        b++;
    }
    
    int main()
    {
        int a = 10, b = 20;
        cout << "in main: a = " << a << ", b = " << b << endl;
        func(ref(a), ref(b)); // 虽然传递的是 b 的引用,但函数形参不是引用类型
                              // ,所以函数内的 b 是一个拷贝
        cout << "in main: a = " << a << ", b = " << b << endl;
        return 0;
    }
    

    输出:

    in main: a = 10, b = 20
    in func: a = 10, b = 20
    in main: a = 11, b = 20
    
  4. T&reference_wrapper 区别

    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";    // true    
        cout << is_same<int&, decltype(r)>::value << "\n";          // false
        cout << (&x == &r.get()) << "\n";                           // true
        r = y;
        cout << (&y == &r.get()) << "\n";                           // true
        r.get()=70;
        cout << y;                                                  // 70
        return 0;
    }
    
  5. 包裹函数指针

    个人感觉,可以替代 函数指针 了,类似 std::function

    void func(int a, int b)
    {
        cout << "a = " << a <<",";
        cout << "b = " << b << endl;
    }
    
    void func1(int i)
    {
        cout << "i = " << i << endl;
    }
    
    void func2(const reference_wrapper<void(int,int)>& f){
        cout << "in func2 invoke f:" << endl;
        f(10, 20);
    }
    
    int main()
    {
        // 包裹函数指针
        int x = 5, y = 7;
        reference_wrapper<void(int,int)> f0 = func;
        f0(x, y);       // a = 5,b = 7
        func2(f0);      // in func2 invoke f:
                        // a = 10,b = 20
    
        auto f1 = std::ref(func);
        f1(5,7);        // a = 5,b = 7
    
        using Examp = reference_wrapper<void(int)>;
        Examp f = func1;
        f(10);          // i = 10
    
        using ExampFc = function<void(int)>;
        ExampFc ff = func1;
        ff(20);         // i = 20
    
        return 0;
    }
    

参考:

  1. std::reference_wrapper
  2. C++ Difference between std::ref(T) and T&?
  3. C++11中std::reference_wrapper的理解