Loop over all the elements in a container and call a member function (with arguments) on each element
I want to introduce one more std::bind trick. In part 1 and part 2 the functions called were non-member functions and we were passing each element of the container into the function as an argument. In this installment we are going to call a member function on each element in the container. We’ll extend our set of declarations to include a member function on class T
:
class T
{
public:
void mf_int( int ) const;
...
};
std::vector< T > v_T;
We have a vector full of objects of type T
, we want to call the member function mf_int
on each object in that vector, and we have to pass an integer argument to mf_int
(I am skipping the example where we don’t have to pass any additional arguments to the function).
Let’s start off with the “old style” solution:
Solution #0
int j( 7 ); for( std::vector< T >::iterator i( std::begin( v_T ) ); i != std::end( v_T ); ++i ) { i->mf_int( j ); }
The range-based for version of the solution is as expected:
Solution #1
for( T const& t : v_T ) { t.mf_int( j ); }
The lambda function version also holds no surprises:
Solution #2
std::for_each( std::begin( v_T ), std::end( v_T ), [ j ]( T const& t ) { t.mf_int( j ); } );
The std::bind version looks a little different though:
Solution #3
using namespace std::placeholders; std::for_each( std::begin( v_T ), std::end( v_T ), std::bind( &T::mf_int, _1, j ) );
The std::bind statement includes something new. &T::mf_int
refers to a member function of class T
– the function T::mf_int
. When std::bind sees a member function (as opposed to a regular function) as its first argument, it expects the second argument to be the object on which to call the member function. In this case since the second argument is _1
, it will call the member function T::mf_int
on every element of the container. There is an additional argument to std::bind (j
) which will be passed as a parameter to T::mf_int
.
Having said above that I was skipping the example where we don’t have to pass any additional arguments to the function I want to mention that example briefly in connection with std::mem_fn, another function adapter (std::bind is a function adapter).
std::mem_fn provides a shorter way to specify that you want to call a member function with no arguments. Let’s add a new declaration to class T
:
class T { public: void mf_int( int ) const; void mf_void() const; ... };
When we use std::mem_fn we don’t need to specify the placeholder _1
:
std::for_each( std::begin( v_T ), std::end( v_T ), std::mem_fn( &T::mf_void ) );
std::mem_fn only works for member functions taking no arguments.
We can also use adobe::for_each:
Solution #4
adobe::for_each( v_T, std::bind( &T::mf_int, _1, j ) );
Wrap up
When we’re using std::bind we always specify the function we are going to call as the first argument. If the function we are going to call is a member function we specify the object on which we are going to call the member function second. Any additional parameters follow.
One thought on “No raw loops 3 – member functions”