Chapter 7. The mem_fn Function Template

The conditionings associated with a particular class …produce habitus, structured structures predisposed to function as structuring structures ….

The Logic of Practice
PIERRE BOURDIEU, TRANSLATED BY RICHARD NICE

template <class Ret, class Ty>
  unspecified mem_fn(Ret Ty::*pm);

The function template returns a simple call wrapper cw, with a weak result type (see Section 6.2), such that the expression cw(a1, a2, …, aN) is equivalent to INVOKE (pm, a1, a2, …, aN) (see Section 6.2).

The returned call wrapper is derived from std::unary_function<cv Ty*, Ret>—hence defining the nested type result_type as a synonym for Ret and the nested type argument_type as a synonym for cv Ty*— only if the type Ty is a pointer to member function with cv-qualifier cv that takes no arguments.

The returned call wrapper is derived from std::binary_function<cv Ty*, T2, Ret>—hence defining the nested type result_type as a synonym for Ret, the nested type first argument_type as a synonym for cv Ty*, and the nested type second argument_type as a synonym for T2—only if the type Ty is a pointer to member function with cv-qualifier cv that takes one argument, of type T2.

This means that you can call the function template mem_fn with a pointer to a class member and get back an object that acts like an ordinary function but uses its first argument to identify the object that the member pointer should be applied to.

Example 7.1. Binding to Object (funobjmem/bindobj.cpp)


#include <functional>
#include <memory>

#include <iostream>
using std::tr1::mem_fn; using std::tr1::shared_ptr;
using std::cout;

class C
  { // simple class with member function
public:
  C(int i0 = 0) : i(i0) {}
  void show() const
    { // show contents
    cout << i << ' ';
    }
private:
  int i;
  };

template <class Fty, class Ty>
void apply(Fty fn, Ty obj)
  { // call a function object with one argument
  fn(obj);
  }

int main()
  { // demonstrate simple use of mem_fn
  C c0(0);
  C *cp = new C(1);
  shared_ptr<C> sp(new C(2));
  void (C::*mptr)() const = &C::show;

  apply(mem_fn(mptr), c0); // equivalent to (c0.*mptr)()
  apply(mem_fn(mptr), cp); // equivalent to (cp->*mptr)()
  apply(mem_fn(mptr), sp); // equivalent to ((*sp).*mptr)()

  delete cp;
  return 0;
  }


As you can see, the object that this code creates with mem_fn(mptr) can be called with an object, a pointer, or a shared_ptr as its argument; the compiler—with a little help from some metaprogramming in the <functional> header—figures out how to call the object. This is a big improvement over the standard C++ library’s std::mem_fun and std::mem_fun_ref, which require you to decide at the point where you create the call wrapper whether you are going to call it with a pointer or an object.

Of course, you can also call member functions that take their own set of arguments. You simply pass those arguments at the point where you call the call wrapper, after the argument that gives the object.

Example 7.2. Additional Arguments (funobjmem/additional.cpp)


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

class C
  { // simple class with member functions
public:
  C(int i0 = 0) : i(i0) {}
  void show() const
    { // show contents
    cout << "in show: " << i << ' ';
    }
  void one_arg(int j) const
    { // member function taking one argument
    cout << "in one_arg: " << i
         << "," << j << ' ';
    }
  void two_args(int j, int k) const
    { // member function taking two arguments
    cout << "in two_args: " << i
         << "," << j << "," << k << ' ';
    }
private:
  int i;
  };

int main()
  {
  C c(1);
  int two = 2;
  int three = 3;
  mem_fn(&C::show)(c);               // c.show();
  mem_fn(&C::one_arg)(c, two );       // c.one_arg(two);
  mem_fn(&C::two_args)(c, two, three); // c.two_args(two, three);
  return 0;
  }


For backward compatibility (see Section 6.5), the object returned by a call to mem_fn is derived from std::unary_function or std::binary_function when appropriate. This defines the nested types that are used by callable objects from the standard C++ library. When the argument to mem_fn is a pointer to a member function of a class Ty and the function takes no arguments, the type of the returned object is derived from unary_function, instantiated with one argument that names the type Ty*[1] and one argument that names the result type. When the argument to mem_fn is a pointer to a member function of a class Ty and the function takes one argument, the type of the returned object is derived from binary_function, instantiated with one argument that names the type Ty*, one argument to pass to the member function, and one argument that names the result type.

Example 7.3. Nested Types (funobjmem/nested.cpp)


#include <functional>
#include <iostream>
#include <typeinfo>
#include <utility>
using std::tr1::mem_fn;
using std::unary_function; using std::binary_function;
using std::cout;

void show_types(…)
  { // general function
  cout << "not unary_function or binary_function ";
  }

template <class Ty, class Ret>
void show_types(
  const unary_function<Ty, Ret>& obj)
  { // overload for types derived from unary_function
  typedef unary_function<Ty, Ret> base;
  cout << "unary_function:"
       << typeid(base::result_type).name() << '('
       << typeid(base::argument_type).name() << ") ";
  }

template <class Ty1, class Ty2, class Ret>
void show_types(
  const binary_function<Ty1, Ty2, Ret>& obj)
  { // overload for types derived from binary_function

  typedef binary_function<Ty1, Ty2, Ret> base;
  cout << "binary_function:"
       << typeid(base::result_type).name() << '('
       << typeid(base::first_argument_type).name()
       << ","
       << typeid(base::second_argument_type).name()
       << ") ";
  }

class C
  { // simple class with member functions
public:
  C(int i0 = 0) : i(i0) {}
  void show() const
    { // show contents
    cout << i << ' ';
    }
  void set(int i0)
    { // replace contents
    i = i0;
    }
private:
  int i;
  };

int main()
  { // show nested types
  show_types(mem_fn(&C::show));
  show_types(mem_fn(&C::set));
  return 0;
  }


For member functions that take more than one argument, the type returned by mem_fn has a nested type named result_type that is a synonym for the return type of the member function.

Example 7.4. Nested Type result_type (funobjmem/resulttype.cpp)


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

template <class Ty>

void show_result_type(Ty)
  { // show nested type named result_type
  cout << typeid(Ty::result_type).name() << ' ';
  }

struct S
  { // struct with member functions
  int f0() { return 0; }
  long f1(int) { return 1; }
  void f2(int, int) {}
  double f3(int, int, int) { return 2.0; }
  };

int main()
  { // show nested result  type
  show_result_type(mem_fn(&S::f0)); // S::f0 returns int
  show_result_type(mem_fn(&S::f1)); // S::f1 returns long
  show_result_type(mem_fn(&S::f2)); // S::f2 returns void
  show_result_type(mem_fn(&S::f3)); // S::f3 returns double
  return 0;
  }


We’ve been looking at member functions; you can also call mem_fn with a pointer to member data. The resulting object can be used in the same way as an object that holds a pointer to member function that takes no arguments.

Example 7.5. Pointer to Member Data (funobjmem/memdata.cpp)


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

template <class Ty>
void show_type(Ty)
  { // show the name of a type
  cout << typeid(Ty ).name() << ' ';
  }

struct S
  {
  S() : i(0), j(1) {}
  int i;

  const int j;
  };

int main()
  {
  S s;
  const S cs;
  show_type(mem_fn(&S::i)(s));  // type of s.i
  show_type(mem_fn(&S::i)(cs)); // type of cs.i
  show_type(mem_fn(&S::j)(s));  // type of s.j
  show_type(mem_fn(&S::j)(cs)); // type of cs.j
  }


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 call mem_fn with an argument that isn’t a pointer to member

2. Attempting to call the returned object with a pointer to a type that isn’t the class that the member belongs to or a class derived from that class

3. Attempting to call the returned object with too few arguments

4. Attempting to call the returned object with too many arguments

Exercise 2

Write a class that holds a private data member of type int and has a member function named show that shows the value of that data member. Write a program that creates an object, using std::vector, that can hold objects of this type and populates it with a dozen or so objects with distinct values in their private data member.

1. Use the algorithm std::for_each and std::mem_fun_ref to show the value stored in each of these data objects.

2. Use the algorithm std::for_each and std::tr1::mem_fn to show the value stored in each of these data objects.

Exercise 3

Copy the code from the previous exercise. Change the vector to hold pointers to objects instead of objects, and make all the other changes needed to make the program work correctly.

Exercise 4

Copy the code from the previous exercise. Change the vector to hold std::tr1::shared_ptr objects to point to the contained objects, and make all the other changes needed to make the program work correctly. Caution: Part of the previous program can’t be made to work correctly after this change.

Exercise 5

Write a class that has a member function that takes one argument with a default value. Write a program that calls mem_fn with a pointer to this member function and calls the returned object.

Exercise 6

Write a class that has two member functions with the same name and return type but take two distinct argument lists. Write a program that makes two calls to mem_fn, with pointers to these two member functions, and calls the returned objects.

Exercise 7

Write a class that has a private data member and two access functions, both named value. One version of value should be callable on a modifiable object and should return a reference to the stored data member; the other should be callable only on a const object and should return a const reference to the stored data member. Write a program that makes two calls to mem_fn, with pointers to these two member functions, and calls the returned objects.

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

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