一.bind函数
1.简介:
std::bind
将一个callable object
与其参数绑定在一起,并生成一个新的callable object。通俗的讲,bind可以使函数先获得一部分参数,把函数包装起来,在需要调用函数的时候把剩余的参数补全即可。
用途:bind可以提高函数的通用性,可以使多个不同函数通过绑定参数,变成参数列表相同的函数,对于多态,回调函数的实现有巨大的作用,提高了代码的抽象程度。
2.使用方法:
bind共可以绑定四种函数,分别为 普通函数,类成员函数,类静态函数,lambda表达式,下面将详细介绍四种函数的使用方法。
bind不会对函数的返回值做出改变,bind封装后的函数依旧可以获得返回值。
(1).绑定普通函数
无参:定义一个普通全局函数,bind的参数填入函数名,即可完成最简单的bind函数绑定。通常bind与auto关键字同时使用。被绑定后的函数变为bind对象,可以通过()直接调用。和调用普通函数一样。
#include<functional>
#include<iostream>
using namespace std;
void tes()
{
cout << "tes" << endl;
}
int main()
{
auto ite = std::bind(tes);
ite();
return 0;
}
运行结果如图所示:
有参:对于有参数的函数,可以选择绑定哪些参数,参数的顺序需要顺序连续,若是有的参数不需要绑定,就要使用 std::placeholders::_1 占位标识符。
#include<functional>
#include<iostream>
using namespace std;
void tes(int a,int b,int c,int d)
{
cout << "tes"<< "a :" << a << " b : " << b << " c :" << c << " d : " << d << endl;
}
int main()
{
myclass c;
auto ite = std::bind(tes,100, placeholders::_1, 300, placeholders::_2);
ite(200,400);
return 0;
}
运行结果如图所示:
代码中定义了一个函数test,有四个成员参数,在绑定的时候这四个参数都得出现,要么给传入提供给函数的需要绑定的参数,要么使用占位符。
对于占位符的使用上,需要注意占位符你的每一个占位符对应后面函数的一个输入参数,如_1对应第一个参数,_2对应第二个参数,所以在使用占位符时数字不能大于后面需要传参的个数。
在调用bind绑定的函数时,会根据占位符传参,若是占位符是_4,则对应位置传入是第四个参数。所以可以通过对于合理使用占位符,改变参数位置。
如下:
auto ite = std::bind(tes,placeholders::_4, placeholders::_3, placeholders::_4, placeholders::_4);
ite(100,200,300,400);
auto ite2 = std::bind(tes, 100, placeholders::_2, 300, placeholders::_1);
ite2(200, 400);
运行结果如下:
对于第一个bind函数,我们第一个占位符为_4,所以传入函数的参数为输入的第四个参数,a为400,第二个占位符为_3,所以传入函数的参数为输入的第三个参数,b为300,后面两个与第一个类似。
对于第二个bind函数,我们第一个占位符为_2,所以传入函数的参数为输入参数的二个参数,a为400,第二个占位符为_1,所以传入函数的参数为输入的第一个参数,b为200。
其他函数的参数绑定,与普通函数的参数绑定是一样的,就不再赘述。
(2).绑定类成员函数
bind还可以绑定类的成员函数,此时bind至少需要两个参数,第一个参数为类的成员函数(需要通过 &类名::成员函数 的方式填入参数,第二个参数为类对象或者类对象的this指针,对象地址也可。
#include<functional>
#include<iostream>
using namespace std;
class myclass
{
public:
void myclass_test()
{
cout << "myclass_test" << endl;
}
};
int main()
{
myclass c;
auto ite = std::bind(&myclass::myclass_test,c);
ite();
return 0;
}
运行如图所示:
(3).绑定类静态函数
对于类的静态函数就不用传递第二个参数了,直接通过 &类名::成员函数 的方式填入第一个参数即可。
绑定lamda表达式
还可以由lambda表达式作为第一个参数
#include<functional>
#include<iostream>
using namespace std;
class myclass
{
public:
static void myclass_test()
{
cout << "myclass_test" << endl;
}
};
int main()
{
myclass c;
auto ite = std::bind([]() {cout << " lamda" << endl; });
ite();
return 0;
}
运行结果如图:
3.参数相关的问题:
(1).传递参数存在的问题:
传参过程中需要注意的是参数的传递在bind总是会以复制的方式传递,任何参数被bind绑定时都会被复制一份,然后传递给bind绑定的函数。尽管绑定的函数要的是引用他也是传递他已经复制了的一份。
(2)解决方式:
这个问题可以通过ref()函数和cref()函数解决。当遇到需要绑定引用参数的函数时,则把对以后给变量用ref修饰,若需要的时const类型的引用则用cref修饰。