The usual way to create references is:

int x{1};
int &ref{x};

There is another way to create reference objects using std::reference_wrapper template which creates a wrapper reference object to a value of type T. For example:

int x{1};
std::reference_wrapper<int> ref{x};

This std::reference_wrapper has following properties:

  1. std::reference_wrapper<T> can be implicitly converted to T&. So, when we do std::cout << ref, as std::reference_wrapper<T> can’t be printed, it will implicitly get converted to T& which then gets printed.
  2. std::reference_wrapper<T>::get() member function returns T&. So, ref.get() = 10 changes the value of x.
  3. Operator= will change what std::reference_wrapper<T> is referencing to. For example, if we do ref = y where y is int y{10};, ref is referencing to y. Please note that we can only use lvalue for reassignment here.

For example:

// changing value of x
 
ref.get() = 3;
 
std::cout << x << "\n"; // 3
std::cout << ref << "\n"; // 3
 
int y{10};
ref = y;
 
std::cout << y << "\n"; // 10
std::cout << ref << "\n"; // 10

We can also create std::reference_wrapper to reference const objects. For example:

const int x{10};
std::reference_wrapper<const int> ref{x};
 
ref.get() = 12; // it will fail.

Furthermore, we can create const std::reference_wrapper:

const std::reference_wrapper<int> ref{x};
 
ref = y; // it will fail.

Full example

Following is a full example of using std::reference_wrapper:

#include <iostream>
#include <functional>
 
int main(int argc, char const *argv[])
{
    int x{1};
    int y{2};
    std::reference_wrapper<int> z{x};
    std::cout << z << '\n';
    z = y;
    std::cout << z << '\n';
 
    std::cout << "---------" << '\n';
    std::cout << x << '\n';
    std::cout << y << '\n';
    std::cout << "---------" << '\n';
 
    z.get() = 3;
    std::cout << "---------" << '\n';
    std::cout << x << '\n';
    std::cout << y << '\n';
    std::cout << "---------" << '\n';
    return 0;
}

We need <functional> header file std::reference_wrapper.

std::ref() and std::cref

Prior to C++17, we could not use CTAD and initializing reference wrapper would get long when we need to explicitly specify T as we saw in above example. So, to make this easier, std::ref() and std::cref() functions were provided.

std::ref() takes a lvalue and creates std::reference_wrapper<T>. And std::cref() creates std::reference_wrapper<const T>.

For example:

int a{1};
int b{2};
 
auto a_ref{std::ref(x)};
auto b_ref{std::cref(y)};

So, a_ref is std::reference_wrapper<int> and b_ref is std::reference_wrapper<const int>.

References

  1. https://www.learncpp.com/cpp-tutorial/arrays-of-references-via-stdreference_wrapper/