Home > Articles > Programming > C/C++

C++ Reference Guide

Hosted by

Toggle Open Guide Table of ContentsGuide Contents

Close Table of ContentsGuide Contents

Close Table of Contents

Reference Wrapper

Last updated Jan 1, 2003.

Continuing our journey into the new C++ standard, this time I present another proposal that has been incorporated into the Library Extensions Technical Report: the reference wrapper class.

Rationale

In certain contexts, built-in reference types cannot be used as first class citizens in C++.

For example, you can't define a container of references:

std::vector <int &> vri; //won't compile

In this respect, reference types are different from bare pointers, which can be used as container elements. Additionally, it is sometimes necessary to pass references as arguments to algorithms and functions that would usually create a copy of their arguments.

A reference wrapper class template enables you to wrap a reference in the guise of an object. The object can then be used in contexts in which built-in references won't work. Consider the following example:

void func(int & r)
{
 r++;
}

template<class F, class T> void g(F f, T t) 
{ 
 f(t); 
}

int main()
{
 int i = 0;
 g(func, i);
}

The second parameter of g() is passed by value. To force g() to take a reference instead, a reference wrapper can do the trick.

The reference_wrapper Class Template

reference_wrapper<T> is a copy-constructible and assignable wrapper around an object of type T&. The copy-constructible and assignable properties ensure, among other things, that reference_wrapper object can be used as an element of STL containers.

The reference_wrapper class and its helper functions are declared in the <utility> header. This header, as you probably know, already contains several other facilities such as auto_ptr.

There are two helper functions: ref() and cref() create a reference_wrapper object that wraps their argument. cref() returns a const T& wrapper object whereas ref() returns a T& wrapper object.

NOTE

When dealing with plain references and references to const objects, people often use the term "const reference" when they actually mean a reference to a const object. Notice that there's no point in having a const reference in C++ in the first place because a reference, once initialized, can't be bound to a different object.

Notice how the use of a reference_wrapper helps us ensure that the function template g() behaves as if it took a reference rather than a copy of its argument:

int main()
{
 int i = 0;
 g(f, i); //pass i by value
 cout << i << endl; //as expected, 0 
 g(f, ref(i)); //bind a reference to i and pass it as arg
 cout << i << endl; // output: 1
}

Let's look at what this program does. First, the function g() is called with two arguments that are passed by value: a function pointer and a copy of i. g() in turns invokes the function bound to f, which increments the copy of i. As expected, when g() returns, the change to the local copy of i ins't reflected in the i that was declared in main(). Therefore, the first cout expression displays 0. In the second call to g(), the ref() helper function creates a temporary reference_warpper() that is bound to i. The side effects of func() are therefore reflected in i after the call and the second cout expression displays 1.

reference_wrapper can be used where ordinary references cannot, such as in containers:

std::list<int> num;
std::vector<reference_wrapper<int> > 
 num_refs; // a list of references to int

for(int i = 0; i < 10; ++i) 
{
 numbers.push_back(2*i*i^4 - 8*i + 7); //ordinary copy semantics
 num_refs.push_back(
//create a reference to the last element in nums
 ref(numbers.back()));
}

A reference_wrapper enables you to pass T& as an argument to algorithms that expect the underlying type, i.e., T:

std::sort(num_refs.begin(), num_refs.end());

Using reference_wrapper with Tuples

reference_wrapper also enables you to create tuples of references and references to const in cases where the tuple class would use the underlying, non-cv-qualified type instead:

void f(const A& ca, B& b)
{
 make_tuple(ca, b); // returns tuple<A, B>
}

To override the default behavior of make_tuple, use ref() and cref() like this:

A a; B b; const A ca=a;
make_tuple( cref(a), b); // tuple <const A&, B> (a,b)
make_tuple( ref(a), b); // tuple <A&, B> (a,b)
make_tuple( ref(a), cref(b) ); // tuple <A&, const B&> (a,b)

Summary

The reference_wrapper utility class and its helper functions exemplify how a small library can be neatly incorporated into C++ to fill a few syntactic lacunae. This type of solution is preferable because it guarantees that existing compilers can cope with new C++ code without requiring upgrades and more importantly -- without causing existing code to break.