std::bind in C++
First of all, let’s remember what is functor, that is, function object.
A function object, also known as a functor, is an object in C++ that acts like a function. Functors are instances of classes or structures that implement the operator() method. This allows them to be called just like regular functions, and they can hold state or behavior in a way that regular functions cannot.
I think that software developer’s best understand a concept is code :)
Here is a functor;
class Functor
{
public:
int operator()(int a, int b)
{
return a < b;
}
};
Well, what is std::bind?
std::bind is a function provided by the C++ Standard Library that allows you to create function objects ( functors) that "bind" together function arguments and parameters. It is often used to transform functions or function objects, adapting them to different argument sets or for use with other algorithms.
std::bind is part of the C++ Standard Library and is defined in the <functional> header. It's particularly useful in scenarios where you need to create new callable objects with specific arguments, especially when working with standard algorithms like std::for_each, std::transform , and others.
Let’s start with a simple example;
#include <iostream>
#include <functional>
void func(int x, int y)
{
std::cout<<"x: "<<x<<" y: "<<y<<"\n";
}
int main()
{
auto f = std::bind(func, 10, 20);
f();
return 0;
}
the std::bind function returns a function object. If we call the functor returned from the std::bind function with the function call operator as in the example above, we call the wrapped func() function with parameters 10 and 20. So output;
Now let’s do an example like this: Our func() function should always take the value 10 as the first parameter, and the second parameter should take the value that we passed to the function objection’s function call operator.
#include <iostream>
#include <functional>
void func(int x, int y)
{
std::cout<<"x: "<<x<<" y: "<<y<<"\n";
}
int main()
{
auto f = std::bind(func, 10, std::placeholders::_1);
f(5);
return 0;
}
So, the call f(5) effectively invokes func(10, 5). This is a common use case for std::bind where you can partially bind arguments and provide the remaining arguments when you call the resulting function object.
Let’s look at different examples and outputs below.
auto f = std::bind(func, std::placeholders::_1, std::placeholders::_1);
auto f = std::bind(func, std::placeholders::_2, std::placeholders::_1);
f(5,3);
I think we could understand it better with examples.
std::bind is a generic wrapper so we can wrap also a member function of a class, we can wrap a lambda.
#include <iostream>
#include <functional>
class MyClass
{
public:
int func(int x)
{
std::cout<<"x: "<<x<<"\n";
return x*x;
}
};
int main()
{
MyClass myClassObj;
auto f = std::bind(&MyClass::func, myClassObj, std::placeholders::_1);
int retVal = f(55);
std::cout<<retVal<<"\n";
return 0;
}
In this example, std::bind takes three arguments:
- The first argument is the member function we want to bind, which is &MyClass::func. We use the address of operator & to specify the member function.
- The second argument is the object on which the member function should be called, which is myClassObj. This binds the member function to myClassObj.
- The third argument is a placeholder std::placeholders::_1 , indicating that when you call f() with an argument, that argument will be passed as the first argument to the member function.
We called the function object f() with the argument 55. This effectively invokes the member function myClassObj.func(55).
std::bind also used with lambda;
#include <iostream>
#include <functional>
int main()
{
auto f = std::bind( [](int x, int y){
return x*y;
},
std::placeholders::_1,std::placeholders::_2 );
int retVal = f(9,7);
std::cout<<retVal<<"\n";
return 0;
}
Implementation of an Adaptor with std::bind()
We use callbacks a lot.Sometimes, when assigning callbacks to each other, we may need to assign them to functions with different numbers of parameters. std::bind is used very often in these situations.
Let’s look at the example below;
#include <iostream>
#include <functional>
class Draw2Point
{
private:
std::function<void(int,int)> _callBack;
public:
void setCallback(const std::function<void(int,int)> &cb)
{
_callBack = cb;
}
void draw(int x, int y)
{
_callBack(x,y);
}
};
class Draw3Point
{
public:
void draw(int x, int y, int z)
{
std::cout<<"x: "<<x<<" y: "<<y<<" z: "<<z<<"\n";
}
};
int main()
{
Draw2Point draw2Point;
Draw3Point draw3Point;
draw2Point.setCallback(std::bind(&Draw3Point::draw, draw3Point,
std::placeholders::_1,std::placeholders::_2, 70));
draw2Point.draw(10,20);
return 0;
}
Draw2Point is a class that has a private member variable _callBack , which is a std::function object. It is used to store a function that takes two integers as arguments and returns void . In This Class, The draw() method takes two integers (x and y) and invokes the function stored in _callBack with these arguments.
Draw3Point is another class that contains a draw() method, which takes three integers (x, y and z ) and prints their values to the console.
In the main function, We set the callback function for draw2Point using std::bind(). We bind the draw() method of draw3Point to the draw2Point object. The std::placeholders::_1 and std::placeholders::_2 are used to indicate that the first and second arguments to the draw2Point object should be passed as the first and second arguments to the draw()method of draw3Point, and 70 is bound as the third argument.
As a result output is like follow;