2.5.10 Reference Wrapper

What was the problem

Be it C++11 or before, template argument deduction never pick a reference. So, for example, if we wanted to create an std::pair<int, int&>, we could not use std::make_pair:

int a; 
int b; 
 
// Ok in C++11, not before. The members of the pair are references to 
// a and b. 
std::pair<int, int&> pair_1(a, b); 
 
// Not ok, std::make_pair returns an std::pair<int, int>. 
std::pair<int, int&> pair_2 = std::make_pair(a, b); 
 
// Not ok in C++11 and before, for different reasons. 
std::pair<int, int&> pair_3 = std::make_pair<int, int&>(a, b);
How the Problem is Solved

PIC <utility>

The std::ref() function (as well as std::cref()) introduced in C++11 will help us with this problem. They both create a reference wrapper for their argument (non const or const, respectively), that is implicitly convertible to a raw reference.

int a; 
int b; 
 
// Ok, std::make_pair returns an 
// std::pair<int, std::reference_wrapper<int>>, which is itself 
// convertible to std::pair<int, int&>. 
std::pair<int, int&> pair_make = std::make_pair(a, std::ref(b));

This is especially useful when binding variables that we don’t want to copy.

#include <algorithm> 
#include <cstdio> 
#include <functional> 
 
struct capacity_tracker 
{ 
  // Decrease the capacity by the given value if it is not too much. Returns 
  // false if the capacity has been decreased, true otherwise. 
  // 
  // Yes, the meaning of the return value is crap. It is just for the example, 
  // so it matches the expectations of std::find() below. Don’t do that at home. 
  bool operator()(int value) 
  { 
    if (capacity < value) 
      return true; 
 
    capacity -= value; 
    return false; 
  } 
 
  int capacity; 
}; 
 
int main() 
{ 
  capacity_tracker tracker = { 10 }; 
  const int values[] = { 3, 1, 2, 4, 5, 8, 6, 7 }; 
 
  // Decrease the capacity by the given values until the capacity becomes lower 
  // than the value. The capacity is decreased along the way and thus reflects 
  // the final value at the end. 
  // 
  // Even though the returned value is correct, the final capacity in the 
  // tracker will be incorrect. Indeed, it is copied in the call to 
  // std::find_if(), so any change has no impact on the local variable. 
  const int* overflow = std::find_if(values, values + 8, tracker); 
 
  printf 
    ("remaining capacity: %d, overflow with %d\n", tracker.capacity, *overflow); 
 
  // This one will work correctly, because a reference to the tracker is passed 
  // to std::find_if. 
  overflow = std::find_if(values, values + 8, std::ref(tracker)); 
 
  printf 
    ("remaining capacity: %d, overflow with %d\n", tracker.capacity, *overflow); 
 
  return 0; 
}