R1 recently enhanced the standard header
How do you pass references as arguments to algorithms? How do you create containers of references?
Use reference_wrapper and its associated helper functions ref() and cref().
Demonstrating the Problem
C++98 argument deduction rules don’t always let you pass references to functions and algorithms, even when the arguments used are references. This problem is quite common in algorithms that forward their arguments to other callable entities or when constructors forward their arguments to base class constructors. The following code listing demonstrates this problem:
void func(int & ri){ ++ri;}template void g(F f, T t) { f(t); }int main(){ int n = 0; int& rn=n; g(func, rn); cout
You'd expect that after calling g(), the value of n would change to 1. However, func() actually gets a copy of n, not a reference to n. Changing the signature of g() to:
template void g(F f, T& t)
causes other problems (for instance, when calling g() with rvalue arguments) so this option is ruled out.
This phenomenon is known as the argument forwarding problem. It can lead to bugs that are very hard to detect, especially when working with high-level libraries of algorithms.
Containers manifest a similar problem. Containers of references can be useful in simulating heterogeneous containers?a topic that I've discussed here more than once. However, it's impossible to create such containers in C++98. What may look like a container of references is actually an ordinary container of value objects. This happens because the references are implicitly replaced with value copies of the original argument:
int n=0;int& rn=n;vector vi;vi.push_back(rn); ++vi[0]; // modifies vi's copy of n, not n itselfcout
While this behavior is desirable in many cases, there are times when you really need to store references in containers. Changing the template argument to int& certainly won't help because the generation of the vector
vector vi; //compilation error
Enter reference_wrapper
std::tr1::reference_wrapper
#include using std::tr1::reference_wrapper;int n=0;//simulate a vector of int&vector > vi;vi.push_back( reference_wrapper(n));++vi[0]; cout
Second Helpings
The helper function ref():
reference_wrapper ref(T& t);
can be used as a short and convenient alternative to typing reference_wrapper
//same as vi.push_back( reference_wrapper(n));vi.push_back(ref(n));
In places where a reference to a const object is needed, use the helper function cref():
reference_wrapper cref(const T& t);
cref() takes a reference to a const object and returns a matching reference_wrapper
#include #includeusing std::tr1::tuple;using std::tr1::make_tuple;A a; const A ca = a;tuple cra(cref(ca));make_tuple(ref(a)); // tuple tuple t(a);
Author's Note: Technically speaking, const T& is a (non-const) reference to const T, not a const reference to T (C++ doesn't have const references anyway). However, the term "const reference" is used frequently in the C++ literature to denote "reference to const". |
Similarly, a reference wrapper can be used with the std::tr1::function facility to create references to function objects and references to const function objects:
class Data {private: vector > records;public: bool operator()(int x, int y) { records.push_back(make_pair(x, y)); return x func = ref(rec);
Wrap up
The reference wrapper library is a small, but valuable, enhancement to standard C++. Several other TR1 components, like tuples and std::tr1::function, depend on it. As you have seen, this small library has useful applications in everyday C++ programming as well.