A proposal to add a reference wrapper to the standard library (revision 1)

Douglas Gregor

Peter Dimov


Document number: N1453=03-0036
Revises document number: N1436=03-0018
Date: 9 April 2003
Project: Programming Language C++, Library Working Group
Reply-to: Doug Gregor

Introduction

This proposal defines a small library addition for passing references to function templates (algorithms) that would usually take copies of their arguments. It defines the class template reference_wrapper and the two functions ref and cref that return instances of reference_wrapper.

reference_wrapper<T> is a CopyConstructible and Assignable wrapper around a reference to an object of type T. It provides an implicit conversion to T&, often allowing the function templates to work on references unmodified. Some library components that would not work on references unmodified may instead detect reference_wrapper and alter their semantics accordingly, e.g., those in the Tuple and Function Object Wrapper proposals.

This proposal is based on the Boost.Ref library.

Usage Examples

reference_wrapper can be used in places where argument deduction would not deduce a reference, e.g., when forwarding arguments:

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

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

int main()
{
  int i = 0;
  g(f, i);
  cout << i << endl; // 0
  g(f, ref(i));
  cout << i << endl; // 1
}

In particular, this can be used to overcome the limitations of forwarding constructor arguments:

struct X
{
  explicit X(int & r);
};

template<class T> struct wrapper
{
  T t;
  template<class A1> explicit wrapper(A1 const & a1): t(a1) {}
};

int i = 0;
wrapper<X> w1(i); // error
wrapper<X> w1(ref(i)); // OK

More information on the forwarding problem is given in N1385.

reference_wrapper can be used where ordinary references cannot, e.g., in containers and (by way of implicit conversion) function calls that expect the underlying type.

std::list<int> numbers;
std::vector<reference_wrapper<int> > number_refs;
for(int i = 0; i < 100; ++i) {
  numbers.push_back(4*i*i^2 - 10*i + 3);
  number_refs.push_back(ref(numbers.back()));
}

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

Additional examples are given in the Tuple and Function Object Wrapper proposals.

reference_wrapper contains an overloaded function call operator to enable passing function object references to standard algorithms. This capability is particularly useful for passing function objects that cannot be copied or stateful function objects:

struct counting_less {
  typedef bool result_type;

  template<typename T> bool operator()(const T& x, const T& y) 
  {
    ++count;
    return x < y;
  }

  int count;
};

// ...

vector<int> elements;
// fill elements
counting_less cl;
sort(elements.begin(), elements.end(), ref(cl));
std::cout << cl.count << " comparisons in sort\n";

Impact on the standard

This proposal defines a pure library extension. . A new class template reference_wrapper is proposed to be added to the standard header <utility> with two supporting functions.

Proposed Text

Header <utility>

namespace std {
  template<typename T> class reference_wrapper;
  template<typename T> ref(T&);
  template<typename T> cref(const T&);
}

Class template reference_wrapper

std::reference_wrapper — Contains a reference to an object of type T.

Synopsis

template<typename T> 
class reference_wrapper {
public:
  // types
  typedef T type;

  // construct/copy/destruct
  explicit reference_wrapper(T&);

  // access
  operator () const;
  get() const;

  // invocation
  template<typename T1, typename T2, ..., typename TN> 
    typename result_of<T(T1, T2, ..., TN)>::type operator()(T1, T2, ..., TN) const;
};

// constructors
template<typename T> ref(T&);
template<typename T> cref(const T&);

Description

reference_wrapper<T> is a CopyConstructible and Assignable wrapper around a reference to an object of type T.

reference_wrapper defines the member type result_type in the following cases:

  1. T is a function pointer, then result_type is the return type of T.
  2. T is a pointer to member function, then result_type is the return type of T.
  3. T is a class type with a member type result_type, then result_type is T::result_type.

reference_wrapper construct/copy/destruct

  1. explicit reference_wrapper(T& t);

    Effects: Constructs a reference_wrapper object that stores a reference to t.
    Throws: Does not throw.

reference_wrapper access

  1. operator () const;

    Returns: The stored reference.
    Throws: Does not throw.

  2. get() const;

    Returns: The stored reference.
    Throws: Does not throw.

reference_wrapper invocation

  1. template<typename T1, typename T2, ..., typename TN> 
      typename result_of<T(T1, T2, ..., TN)>::type operator()(T1 a1, T2 a1, ... , 
                                                              TN aN) const;

    Effects: f.get()(a1, a2, ..., aN)
    Returns: The result of the expression f.get()(a1, a2, ..., aN)

reference_wrapper constructors

  1. template<typename T> ref(T& t);

    Returns: reference_wrapper<T>(t)
    Throws: Does not throw.

  2. template<typename T> cref(const T& t);

    Returns: reference_wrapper<const T>(t)
    Throws: Does not throw.

Additions to "Implemention Quantities"

Maximum number of arguments forwarded by reference_wrapper [10]

Relationship with other proposals

Class template reference_wrapper and function templates ref and cref were also defined in documents N1402 (Function object wrappers) and N1403 (Tuples). The definition in this proposal is compatible with the definitions in both these proposals; this proposal is meant only to clarify the role of reference_wrapper and its helper functions, as requested by the committee.

Revisions

  • Use result_of for the return type of operator().
  • Constructor is now explicit (this was intended previously, and present in prior proposals).

Acknowledgements

Much of the text of this proposal comes from the Boost.Ref library documentation written by Peter Dimov. The first two examples were presented by Peter Dimov in c++std-ext-5635.

References

  1. Järvi, Jaakko. Proposal for adding tuple types into the standard library. http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2002/n1403.pdf

  2. Gregor, Doug. A Proposal to add a Polymorphic Function Object Wrapper to the Standard Library. http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2002/n1402.html

  3. Dimov, Peter. The Forwarding Problem: Arguments. http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2002/n1385.htm

  4. The Boost.Ref Library. http://www.boost.org/libs/bind/ref.html