mem_fn
Function TemplateThe 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
}
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
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.
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.
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.
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.
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.
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.
18.226.185.196