Chapter 8. The reference_wrapper Class Template

These are only aliases. Their real names are
Stuhldreher, Miller, Crowley, and Layden.

— Story on Notre Dame football victory over Army
GRANTLAND RICE

The class template reference_wrapper creates objects that act like references but can be copied. Ordinary references can’t be copied.

Example 8.1. Copying References (funobjref/refcopy.cpp)


#include <functional>
using std::tr1::reference_wrapper;

class ref
  { // simple class containing reference
public :
  ref(int& i) : member(i) {}
private :
  int& member;
  };

class refwrap
  { // simple class containing reference_wrapper
public :
  refwrap(int& i) : member(i) {}
private :
  reference_wrapper<int> member;
  };

void f()
  { // demonstrate copying
  int i, j;
  ref r0(i);
  ref r1(j);
  r1 = r0 ;        // error: ref can't be copied


  refwrap rw0(i);
  refwrap rw1(j);
  rw1 = rw0 ;     // okay: refwrap can be copied
  }


An object of type reference_wrapper<Ty> can be implicitly converted to a reference to Ty and has a member function, named get, that returns a reference to Ty. Finally, if the type Ty is a callable type, you can use the object’s function call operator to call the object it refers to.

template<class Ty>
   class reference_wrapper
    : public unary_function<T1, Ret>         // see Section 8.2
    : public binary_function<T1, T2, Ret>    // see Section 8.2
  {
public :
  typedef Ty type;
  typedef T0 result_type;                     // see Section 8.2
  explicit reference_wrapper(Ty&);
  Ty& get() const;
  operator Ty&() const;
  template <class T1, class T2,…, class TN>
  typename result_of<T(T1, T2,…, TN)>::type
  operator() (T1&, T2&, …, TN&) const ;     // see Section 8.3
  };

8.1. Creation

You can create a reference_wrapper object directly with the template’s constructor, and you can create a reference_wrapper object indirectly by calling the functions ref and cref.

explicit reference_wrapper::reference_wrapper(Ty& obj);

The constructor constructs an object that refers to obj.

Example 8.2. Construction (funobjref/construct.cpp)


#include <functional>
#include <iostream>
using std::tr1::reference_wrapper;

using std::cout;

int main()
  { // demonstrate basic use of reference_wrapper
  int Stuhldreher = 3;
  reference_wrapper<int> rw(Stuhldreher);
  cout << rw << ' ';           // displays value of Stuhldreher
  Stuhldreher = 4;
  cout << rw << ' ';           // displays new value of Stuhldreher
  rw.get() = 5;                 // changes value of Stuhldreher
  cout << Stuhldreher << ' ';  // displays new value
  return 0;
  }


template <class Ty>
  reference_wrapper<const Ty> cref(
    const Ty& obj);
template <class Ty>
  reference_wrapper <const Ty> cref(
    reference_wrapper <Ty> rw);
template <class Ty>
  reference_wrapper <Ty> ref(
    Ty& obj);
template <class Ty>
  reference_wrapper <Ty> ref(
    reference_wrapper <Ty> rw);

The first function template returns an object of type reference_wrap-per<const Ty> that refers to obj. The second function template returns an object of type reference_wrapper<const Ty> that refers to rw.get(). The third function template returns an object of type reference_wrap-per<Ty> that refers to obj. The fourth function template returns an object of type reference_wrapper<Ty> that refers to rw.get().

Example 8.3. Function Templates ref and cref (funobjref/refcref.cpp)


#include <functional>
#include <iostream>
using std::tr1::reference_wrapper;
using std::tr1::ref; using std::tr1::cref;
using std::cout;

void show(int& i)
  { // show value referred to by reference to int
  cout << "int &:" << i << ' ';
  }

void show(const int& i)
  { // show value referred to by reference to const int
  cout << "const int&:" << i << ' ';
  }

int main()
  { // demonstrate use of ref and cref
  int Miller = 3;
  show(ref(Miller));    // calls show(int&);
  reference_wrapper<int> rw0(Miller);
  show(ref(rw0));       // calls show(int&);
  show(cref(Miller));   // calls show(const int&);
  reference_wrapper <const int> rw1(Miller);
  show(cref(rw1));      // calls show(const int&);
  return 0;
  }


One important difference between using the constructor for reference_wrapper directly and using either of the functions ref and cref is that these functions return a reference_wrapper<Ty> object, where Ty is the type of their argument. The constructor, on the other hand, can be passed an object of a type that is convertible to the type Ty that the reference_wrapper object holds. Thus, although reference_wrapper itself directly supports polymorphic types, the functions ref and cref do not; it takes a bit of trickery to get these functions to return a reference_wrapper that refers to a base of the type of their argument. We’ll look at how to do that in the exercises.

Example 8.4. Polymorphic Types (funobjref/polymorph.cpp)


#include <functional>
#include <iostream>
using std::tr1::reference_wrapper;
using std::cout;

struct base
  {  // base class
  virtual void show() const


    {  // show name of base class
    cout << "base ";
    }
  };

struct derived0 : base
  { // one derived class
  void show() const
    { // show name of derived class
    cout << "derived0 ";
    }
  };

struct derived1 : base
  { // another derived class
  void show() const
    { // show name of derived class
    cout << "derived1 ";
    }
  };

int main()
  { // demonstrate reference_wrapper's support for polymorphism
  derived0 Crowley ;
  derived1 Layden ;
  reference_wrapper<base> rw0(Crowley);
  rw0.get().show();         // calls derived0::show
  reference_wrapper<base> rw1 (Layden);
  rw1.get().show();         // calls derived1::show
  return 0;
  }


8.2. Nested Types

typedef Ty reference_wrapper::type ;

The nested type reference_wrapper<Ty>::type is a synonym for the template argument Ty.

typedef T0 reference_wrapper::result_type;

The template specialization reference_wrapper<Ty> is derived from std::unary_function<T1, Ret>—hence defining the nested type result_type as a synonym for Ret and the nested type argument_type as a synonym for T1—only if the type Ty is one of the following:

• A function type or pointer to function type taking one argument of type T1 and returning Ret

• A pointer to member function type with cv-qualifier cv that takes no arguments; the type T1 is cv Ty*, and Ret is the return type of the pointer to member function

• A type that is derived from std::unary_function<T1, Ret>

The template specialization reference_wrapper<Ty> is derived from std::binary_function<T1, T2, Ret>—hence defining the nested type result_type as a synonym for Ret, the nested type first_argument_type as a synonym for T1, and the nested type second_argument_type as a synonym for T2—only if the type Ty is one of the following:

• A function type or pointer to function type taking two arguments of types T1 and T2 and returning Ret

• A pointer to member function type with cv-qualifier cv that takes one argument of type T2; the type T1 is cv Ty*, and Ret is the return type of the pointer to member function

• A type that is derived from std::binary_function<T1, T2, Ret>

If it is not derived from unary_function or binary_function, the template specialization defines the nested type result_type according to the rules for a weak result type (see Section 6.2).

8.3. Invocation

typename result_of <Ty(T1, T2, …, TN)>::type
  operator()(T1&, T2&, …, TN&) const;

If the template argument Ty is not a callable type, this operator is not present. For a callable type (see Section 6.1)Ty and an object rw of type reference_wrapper<Ty>, the expression rw(a1, a2, …, aN) is equivalent to INVOKE(rw.get(), a1, a2, …, aN) (see Section 6.2).

When a reference_wrapper object holds a callable object, you can call the reference_wrapper object, which will, in turn, call its target object.

Example 8.5. Invoking (funobjref/invoke.cpp)


#include <functional>
#include <iostream>
using std::tr1::reference_wrapper; using std::tr1::cref;
using std::cout;

void hello()
  {   // simple function
  cout << "Hello, world ";
  }

void goodbye()
  {   // another simple function
  cout << "Goodbye, cruel world ";
  }

int main()
  {   // demonstrate invocation of reference  wrapper object
  typedef void (*const fun)();
  reference_wrapper<fun> rw(&hello);
  rw();           // calls hello
  rw = cref(&goodbye);
  rw();           // calls goodbye
  return 0;
  }


If you look at the declaration of reference_wrapper’s function call operator, you’ll see that all the arguments are passed by reference. This lets you pass modifiable objects to the target object.

Example 8.6. Modifiable Arguments (funobjref/modifiable.cpp)


#include <functional>
#include <iostream>
using std::tr1::reference_wrapper;

using std::cout;

struct S
  {
  void operator()(int& i)
    {   // modify argument
    ++i;
    }
  typedef void result_type;
  };

int main()
  {
  int i = 0;
  S s;
  reference_wrapper<S> rw(s);
  cout << "Before call :" << i << ' ';
  rw(i);
  cout << "After call: "<< i << ' ';
  return 0;
  }


Exercises

Exercise 1

For each of the following errors, write a simple test case containing the error, and try to compile it. In the error messages, look for the key words that relate to the error in the code.

1. Attempting to construct a reference_wrapper<int> object from an object of type const int

2. Attempting to modify an object of type int through an object of type reference_wrapper<const int>

3. Attempting to assign an object of type reference_wrapper<T1> to an object of type reference_wrapper<T2>, where T1 and T2 are unrelated types

4. Attempting to assign an object of type reference_wrapper<T1> to an object of type reference_wrapper<T2>, where T1 is publicly derived from T2

5. Attempting to use a reference_wrapper object to call an object that isn’t callable

6. Attempting to call a target object with the wrong number of arguments

Exercise 2

Write a program that does the following:

1. Creates an object of type int and initializes it to 1

2. Creates an object of type int& and an object of type const int&, both referring to the object of type int

3. Constructs a reference_wrapper object that refers to the int object and a reference_wrapper that refers to the int object but doesn’t allow modification of that object

Exercise 3

Write a program that does the following:

1. Defines a base type and a type derived from the base type

2. Creates an object of the derived type

3. Creates a reference to the base type that refers to the derived object

4. Creates a const reference to the base type that refers to the derived object

5. Constructs a reference_wrapper<base> object that refers to the derived object

6. Constructs a reference_wrapper<const base> object that refers to the derived object

7. Creates a second object of the derived type

8. Uses ref to reassign the first reference_wrapper object to refer to the new object

9. Uses cref to reassign the second reference_wrapper object to refer to the new object

Exercise 4

Write a program that creates a reference_wrapper object that holds a pointer to the function std::cosf. Call the function several times, with different argument values, directly and through the reference_wrapper object, and verify that the results are the same.

Exercise 5

Write a program that defines a class with a member function that takes at least one argument, then creates a reference_wrapper object that holds a pointer to that member function. Create several objects of that class type, and call the member function several times, with different argument values, directly and through the reference_wrapper object, and verify that the results are the same.

Exercise 6

Write a program that defines a class with a member function call operator that takes at least one argument, then creates a reference_wrapper object that holds an object of that type. Call the operator several times, with different argument values, directly and through the reference_wrapper object, and verify that the results are the same.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.216.143.65