In this article we will see how to use std::bind and when to use.

std::bind

std::bind is a Standard Function Objects that acts as a Functional Adaptor i.e. it takes a function as input and returns a new function Object as an output with with one or more of the arguments of passed function bound or rearranged.

Suppose We have a function to add two numbers i.e.

int add(int first, int second)
{
	return first + second;
}

std::bind takes a function as its first parameter and then that function’s argument as its parameter.
auto add_func = std::bind(&add, _1, _2);

Here add_func is a function object i.e. equivalent to add().
std::bind took the first parameter a function i.e. &add and then its arguments as _1 & _2 as his own arguments.

So, whenever we call this new function object i.e.

add_func(4,5);

It will internally call the add() function and pass the first parameter at the place of _1 and second at the place of _2.

So, add_func(4,5) is equivalent to add(4,5).

Now suppose we want to use this add function in a special scenarion where we should fix the first argument to 12 always and let the second argument passed by user i.e.

int x = new_add_func(5);
// Will return 9

We can do this using std::bind,
auto new_add_func = std::bind(&add, 12, _1);

So, when we call new_add_func(5) it will internally call the add() function with first parameter will beĀ  12 always and second parameter will 5 i.e. passed as argument.

We can also rearrange arguments using std::bind() i.e. _1 and _2 etc decides the place of argument to be passed i.e.

auto mod_add_func = std::bind(&add, _2, _1);

When we call mod_add_func(12,15) it is equivalent to calling add(15, 12).

_1 represents the first passed argument and _2 second passed argument. Now while constructing new function object through std::bind we changed the order of arguments by passing _2 first and _1 second in the underlined function.

Use of std::bind in STL algorithms

As std::bind acts as a functional adaptor and gives the a new function objects, hence it is very usefull with many STL algorithms.

For example,
We haveĀ  a list of numbers and we want to count the numbers which are multiple of 5. To achive this we have an existing function i.e.

bool divisible(int num , int den)
{
    if(num % den == 0)
        return true;
    return false;

}

First basic approach to this problem is lets iterate through all elements using for loop, check condition and increment counter i.e.
int approach_1()
{
    int arr[10] = {1,20,13,4,5,6,10,28,19,15};
    int count = 0;
    for(int i = 0; i < sizeof(arr)/sizeof(int); i++)
    {
        if(divisible(arr[i], 5))
            count++;
    }
    return count;

}

 

But this all is done in std::count_if STL algorithm i.e. std::count_if

count_if (InputIterator firstValue, InputIterator lastValue, UnaryPredicate predFunctionObject);

std::count_if Returns the number of elements in the range [firstValue,lastValue) for which predFunctionObject is true.

Now to use this std::count_if in our scenario we need to convert divisible() into a Unary predicate i.e. Fixing second value in function divisible () to 5 always. Let’s do this with std::bind,

int approach_2()
{
    int arr[10] = {1,20,13,4,5,6,10,28,19,15};
    return std::count_if(arr, arr + sizeof(arr)/sizeof(int) , std::bind(&divisible, _1, 5));

}

Here, std::bind(&divisible, _1, 5) Will return a new Function Object that takes only One Argument and checks if it is divissble by 5 or not.

What std::bind returns ?

std::bind returns a function object. In above examples we have either save this new function object in auto variable or used it directly.
But we can also store them using std::function Function object i.e.

std::function<int (int) > mod_add_funcObj = std::bind(&add, 20, _1);

To checkout more on std::function, checkout our next Article.

 

Complete executable code is as follows,

#include <memory>
#include <functional>
#include <iostream>
#include <algorithm>

using namespace std::placeholders;


int add(int first, int second)
{
	return first + second;
}

bool divisible(int num , int den)
{
	if(num % den == 0)
		return true;
	return false;

}
int approach_1()
{
	int arr[10] = {1,20,13,4,5,6,10,28,19,15};
	int count = 0;
	for(int i = 0; i < sizeof(arr)/sizeof(int); i++)
	{
		if(divisible(arr[i], 5))
			count++;
	}
	return count;

}

int approach_2()
{
	int arr[10] = {1,20,13,4,5,6,10,28,19,15};
	return std::count_if(arr, arr + sizeof(arr)/sizeof(int) , std::bind(&divisible, _1, 5));

}

int main()
{
	int x = add(4,5);
	// Will return 9

	// What if we want to fix the first argument
	auto new_add_func = std::bind(&add, 12, _1);

	x = new_add_func(5);
	// Will return 17

	std::cout<<x<<std::endl;



	auto mod_add_func = std::bind(&add, _2, _1);

	x = mod_add_func(12, 15);
	// Will return 27
	std::cout<<x<<std::endl;

	std::function<int (int) > mod_add_funcObj = std::bind(&add, 20, _1);
	x = mod_add_funcObj(15);
	// Will return 35

	std::cout<<x<<std::endl;

	std::cout<<approach_1()<<std::endl;

	std::cout<<approach_2()<<std::endl;
	return 0;
}