A proposal to add a reference wrapper to the standard library

Douglas Gregor

Peter Dimov

Table of Contents

Introduction
Usage Examples
Impact on the standard
Proposed Text
Header <utility>
Header <functional>
Additions to "Implemention Quantities"
Relationship with other proposals
References

Document number: N1436=03-0018
Date: 28 February 2003
Project: Programming Language C++, Library Working Group
Reply-to: Douglas 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 [Järvi02] and Function Object Wrapper [Gregor02] proposals.

This proposal is based on the Boost.Ref library [Boost01].

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 [Dimov02].

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 [Järvi02] and Function Object Wrapper [Gregor02] 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. Additionally, a class template result_of is proposed to be added to the standard header <functional>.

Proposed Text

Header <utility>

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

Class template reference_wrapper

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

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

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

  // invocation
  template<typename T1, typename T2, ..., typename TN> 
    unspecified operator()(T1&, T2&, ..., TN&) const;
};

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

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 with C++ linkage, then result_type is the return type of T.
  2. T is a class type with a member type result_type, then result_type is T::result_type.
reference_wrapper construct/copy/destruct
  1. 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 T&() const;

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

  2. T& get() const;

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

reference_wrapper invocation
  1. template<typename T1, typename T2, ..., typename TN> 
      unspecified operator()(T1& a1, T2& a1, ... , TN& aN) const;

    [[Author's note: if a form of the move semantics proposal [Hinnant02] is accepted, the parameter types should be rvalue references (e.g., T1&&) to properly forward arguments.]]

    [[Author's note: the intention of this operator is to make reference_wrapper<F> behave in function call expressions as if the F& conversion operator were used. We hope that future revisions of the C++ standard will require this as is currently done for user-defined conversions to function pointers.]]

    The return type is the type of the expression f.get()(a1, a2, ..., aN). The implementation may deduce this type via any implementation-defined means. If the implementation cannot deduce the result of the expression f.get()(a1, a2, ..., aN), the return type is result_of<T(T1, T2, ..., TN)>::type.

    Returns: f.get()(a1, a2, ..., aN)

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

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

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

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

Header <functional>

namespace std {
  template<typename T> class result_of;
}

Class template result_of

template<typename T  // Function type F(A1, A2, ..., An)
         > 
class result_of {
public:
  // types
  typedef unspecified type;
};

The expression result_of<F(A1, ..., An)>::type, where n is a nonnegative integer and F is a function object type with arity n, is intended to yield the type of the expression f(a1, ..., an), where f and ai are lvalues of type F and Ai, respectively.

The default behavior of result_of is implementation defined. Implementations are strongly encouraged to supply a functional result of that recognizes functions, function pointers, and function objects that have a nested typedef result_type as F, and define result_of<F(...)>::type accordingly.

result_of can be specialized by users to provide a hint to the implementation.

[[Author's note: this definition of result_of is equivalent to the definition in the Bind proposal [Dimov03]. The uniform return type deduction proposal [Gregor03] further specifies result_of.]]

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 the Function object wrappers [Gregor02] and Tuple [Järvi02] proposals . 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, and also to extend its abilities as a function object.

Class template result_of is also introduced in the Bind proposal [Dimov03] with the same proposed text, and forms the basis for the uniform result type deduction proposal [Gregor03].

References

[Järvi02] Jaakko Järvi, Proposal for adding tuple types into the standard library, C++ committee document N1403=02-0061, November 2002. Available online at http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2002/n1403.pdf

[Gregor02] Douglas Gregor, A Proposal to add a Polymorphic Function Object Wrapper to the Standard Library, C++ committee document N1402=02-0060, October 2002. Available online at http://std.dkuug.dk/jtc1/sc22/wg21/docs/papers/2002/n1402.htm.

[Dimov02] Peter Dimov, Howard E. Hinnant, Dave Abrahams, The Forwarding Problem: Arguments, C++ committee document N1385=02-0043, September 2002. Available online at http://std.dkuug.dk/jtc1/sc22/wg21/docs/papers/2002/n1385.htm

[Boost01] Boost.Ref library, 2001. Available online at http://www.boost.org/libs/bind/ref.html

[Hinnant02] Howard E. Hinnant, Peter Dimov, and Dave Abrahams, A Proposal to Add Move Semantics Support to the C++ Language, C++ committee document N1377=02-0035, September 2002. Available online at http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2002/n1377.htm.

[Dimov03] Peter Dimov, Douglas Gregor, Jaakko Järvi, and Gary Powell, A Proposal to Add an Enhanced Binder to the Library Technical Report, C++ committee document N1438=03-0020, February 2003. Available online at http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1438.html.

[Gregor03] Douglas Gregor, A Uniform Method for Computing Function Object Return Types, C++ committee document N1437=03-0019, February 2003. Available online at http://std.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1437.htm.