19.4.3. Using Member Functions as Callable Objects

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 strings, 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.

Using function to Generate a Callable

One 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);

Using mem_fn to Generate a Callable
Image

To 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&.

Using bind to Generate a Callable

For completeness, we can also use bind10.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

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

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