As we’ve seen, to make a call through a pointer to member function, we must use the .*
or ->*
operators to bind the pointer to a specific object. As a result, unlike ordinary function pointers, a pointer to member is not a callable object; these pointers do not support the function-call operator (§ 10.3.2, p. 388).
Because a pointer to member is not a callable object, we cannot directly pass a pointer to a member function to an algorithm. As an example, if we wanted to find the first empty string
in a vector
of string
s, the obvious call won’t work:
auto fp = &string::empty; // fp points to the string empty function
// error: must use .* or ->* to call a pointer to member
find_if(svec.begin(), svec.end(), fp);
The find_if
algorithm expects a callable object, but we’ve supplied fp
, which is a pointer to a member function. This call won’t compile, because the code inside find_if
executes a statement something like
// check whether the given predicate applied to the current element yields true
if (fp(*it)) // error: must use ->* to call through a pointer to member
which attempts to call the object it was passed.
function
to Generate a CallableOne way to obtain a callable from a pointer to member function is by using the library function
template (§ 14.8.3, p. 577):
function<bool (const string&)> fcn = &string::empty;
find_if(svec.begin(), svec.end(), fcn);
Here we tell function
that empty
is a function that can be called with a string
and returns a bool
. Ordinarily, the object on which a member function executes is passed to the implicit this
parameter. When we want to use function
to generate a callable for a member function, we have to “translate” the code to make that implicit parameter explicit.
When a function
object holds a pointer to a member function, the function
class knows that it must use the appropriate pointer-to-member operator to make the call. That is, we can imagine that find_if
will have code something like
// assuming it is the iterator inside find_if, so *it is an object in the given range
if (fcn(*it)) // assuming fcn is the name of the callable inside find_if
which function
will execute using the proper pointer-to-member operator. In essence, the function
class will transform this call into something like
// assuming it is the iterator inside find_if, so *it is an object in the given range
if (((*it).*p)()) // assuming p is the pointer to member function inside fcn
When we define a function
object, we must specify the function type that is the signature of the callable objects that object can represent. When the callable is a member function, the signature’s first parameter must represent the (normally implicit) object on which the member will be run. The signature we give to function
must specify whether the object will be passed as a pointer or a reference.
When we defined fcn
, we knew that we wanted to call find_if
on a sequence of string
objects. Hence, we asked function
to generate a callable that took string
objects. Had our vector
held pointers to string
, we would have told function
to expect a pointer:
vector<string*> pvec;
function<bool (const string*)> fp = &string::empty;
// fp takes a pointer to string and uses the ->* to call empty
find_if(pvec.begin(), pvec.end(), fp);
mem_fn
to Generate a CallableTo use function
, we must supply the call signature of the member we want to call. We can, instead, let the compiler deduce the member’s type by using another library facility, mem_fn
, which, like function
, is defined in the functional
header. Like function, mem_fn
generates a callable object from a pointer to member. Unlike function, mem_fn
will deduce the type of the callable from the type of the pointer to member:
find_if(svec.begin(), svec.end(), mem_fn(&string::empty));
Here we used mem_fn(&string::empty)
to generate a callable object that takes a string
argument and returns a bool
.
The callable generated by mem_fn
can be called on either an object or a pointer:
auto f = mem_fn(&string::empty); // f takes a string or a string*
f(*svec.begin()); // ok: passes a string object; f uses .* to call empty
f(&svec[0]); // ok: passes a pointer to string; f uses .-> to call empty
Effectively, we can think of mem_fn
as if it generates a callable with an overloaded function call operator—one that takes a string*
and the other a string&
.
bind
to Generate a CallableFor completeness, we can also use bind
(§ 10.3.4, p. 397) to generate a callable from a member function:
// bind each string in the range to the implicit first argument to empty
auto it = find_if(svec.begin(), svec.end(),
bind(&string::empty, _1));
As with function
, when we use bind
, we must make explicit the member function’s normally implicit parameter that represents the object on which the member function will operate. Like mem_fn
, the first argument to the callable generated by bind
can be either a pointer or a reference to a string
:
auto f = bind(&string::empty, _1);
f(*svec.begin()); // ok: argument is a string f will use .* to call empty
f(&svec[0]); // ok: argument is a pointer to string f will use .-> to call empty