本篇来介绍了C++中bind功能。
1 std::bind
在 C++ 里,std::bind 是一个函数模板,其作用是创建一个可调用对象,该对象可绑定到一组参数上。std::bind 的函数原型如下:
template<?class?F,?class...?Args?>
/*unspecified*/?bind(?F&&?f,?Args&&...?args?);
template<?class?R,?class?F,?class...?Args?>
/*unspecified*/?bind(?F&&?f,?Args&&...?args?);
参数
F:这是要绑定的可调用对象(像函数、函数指针、成员函数指针、函数对象等)的类型。
Args:这是要绑定的参数的类型包。
f:需要绑定的可调用对象。
args:要绑定到可调用对象上的参数。
R:可调用对象的返回类型(可选)。
返回值
std::bind
?返回一个未指定类型的可调用对象,这个对象存储了?f 和?args 的副本或者引用,并且可以在后续被调用。
2 实例
2.1 基础的bind功能
被绑定的函数支持参数和返回值,参数通过std::placeholders::_1的形式,注意这里_1是特定的形式,表示第一个参数
//g++ test1.cpp -std=c++11 -o test1
#include?<functional>
#include?<string>
std::string?myFunc(int?a,?float?b)
{
? ??char?buf[256];
? ??sprintf(buf,?"receive a:%d, b:%.2f", a, b);
? ??returnstd::string(buf);
}
int?main()
{
? ??auto?bindFunc =?std::bind(myFunc,?std::placeholders::_1,?std::placeholders::_2);
? ??std::string?res = bindFunc(5,?8.63);
? ??printf("res:%sn", res.c_str());
? ??
? ??return0;
}
示例代码运行结果如下:
2.2 bind时调换参数的顺序
如果调换参数顺序的需求,可以通过指定placeholders的顺序,来实现。
比如,myFunc的第二个参数是float类型,如果在执行调用函数时,第一个参数传入float,则在绑定函数的第一个位置,写为?std::placeholders::_2即可。
//g++ test2.cpp -std=c++11 -o test2
#include?<functional>
#include?<string>
std::string?myFunc(int?a,?float?b)
{
? ??char?buf[256];
? ??sprintf(buf,?"receive a:%d, b:%.2f", a, b);
? ??returnstd::string(buf);
}
int?main()
{
? ??auto?bindFunc =?std::bind(myFunc,?std::placeholders::_2,?std::placeholders::_1);
? ??std::string?res = bindFunc(3.14,?6);
? ??printf("res:%sn", res.c_str());
? ??
? ??return0;
}
示例代码运行结果如下:
2.3 结合C++类使用bind
上面介绍的函数都不涉及到类,而C++中一般都会使用类,在类中以及类中的函数,如果使用bind,主要区别就是要再额外传入对应的类的指针。
这里演示了3种情况:
- MyClass1进行一个实例化,然后在main中bind其成员函数MyClass2是一个单例模式,在main中bind的时候进行实例化MyClass3,演示在类内部进行bind,类的指针就是this指针
 
//g++ test3.cpp -std=c++11 -o test3
#include?<functional>
#include?<string>
class?MyClass1
{
public:
? ??std::string?myFunc(int?a,?float?b)
? ??{
? ? ? ??char?buf[256];
? ? ? ??sprintf(buf,?"receive a:%d, b:%.2f", a, b);
? ? ? ??returnstd::string(buf);
? ? } ? ?
};
class?MyClass2
{
public:
? ??static?MyClass2 &getInstance()
? ??{
? ? ? ??static?MyClass2 instance;
? ? ? ??return?instance;
? ? }
? ??
? ??std::string?myFunc(int?a,?float?b)
? ??{
? ? ? ??char?buf[256];
? ? ? ??sprintf(buf,?"receive a:%d, b:%.2f", a, b);
? ? ? ??returnstd::string(buf);
? ? } ? ?
};
class?MyClass3
{
public:
? ??std::string?myFunc(int?a,?float?b)
? ??{
? ? ? ??char?buf[256];
? ? ? ??sprintf(buf,?"receive a:%d, b:%.2f", a, b);
? ? ? ??returnstd::string(buf);
? ? }?
? ??
? ??void?testBind()
? ??{
? ? ? ??auto?bindFunc =?std::bind(&MyClass3::myFunc,?this,?std::placeholders::_1,?std::placeholders::_2);
? ? ? ??std::string?res = bindFunc(33,?3.45);
? ? ? ??printf("res:%sn", res.c_str());?
? ? } ?
};
int?main()
{
? ? MyClass1 myClass1;
? ??auto?bindFunc1 =?std::bind(&MyClass1::myFunc, &myClass1,?std::placeholders::_1,?std::placeholders::_2);
? ??std::string?res1 = bindFunc1(11,?1.23);
? ??printf("res:%sn", res1.c_str());
? ??auto?bindFunc2 =?std::bind(&MyClass2::myFunc, MyClass2::getInstance(),?std::placeholders::_1,?std::placeholders::_2);
? ??std::string?res2 = bindFunc1(22,?2.34);
? ??printf("res:%sn", res2.c_str());
? ??
? ? MyClass3 myClass3;
? ? myClass3.testBind();
? ? ??
? ??return0;
}
示例代码运行结果如下:
2.4 std::ref的使用
在进行bind的时候,也可以不使用placeholders占符,直接传入具体的参数。
这里要注意,直接传入值,即使函数参数定义的是引用,但实际效果也是按值传递。如果需要按引用传递,需要使用std::ref,如下例中的第一个演示。当然,如果是使用placeholders占符,就不需要考虑std::ref了,就会正常的按定义的引用类型运行。
//g++ test4.cpp -std=c++11 -o test4
#include?<functional>
#include?<string>
std::string?myFunc(int?&a,?float?&b)
{
? ??char?buf[256];
? ??sprintf(buf,?"receive a:%d, b:%.2f", a, b);
? ? a +=?1;
? ? b +=?1;
? ??returnstd::string(buf);
}
int?main()
{
? ??int?a =?100;
? ??float?b =?66.88;
? ??printf("a:%d, b:%.2fn", a, b);
? ??auto?bindFunc1 =?std::bind(myFunc, a,?std::ref(b));
? ??std::string?res1 = bindFunc1();
? ??printf("res1:%sn", res1.c_str());
? ??printf("a:%d, b:%.2fn", a, b);
? ??
? ??auto?bindFunc2 =?std::bind(myFunc,?std::placeholders::_1,?std::placeholders::_2);
? ??std::string?res2 = bindFunc2(a, b);
? ??printf("res2:%sn", res2.c_str());
? ??printf("a:%d, b:%.2fn", a, b);
? ??
? ??return0;
}
示例代码运行结果如下:
2.5 将bind作为函数参数实现函数传递
最后来看一个特殊的,函数的参数是一个函数类型,如下面的MyClass类中的myFunc,它需要传入一个函数,这个函数有两个float类型的参数,并且返回一个float,在myFunc中定义了两个参数的具体的值。
这个有什么用呢,比如在MyCalc类中定义sum求和函数和sub求差函数,这样MyClass类就可以使用外部的MyCalc类中定义的函数功能,来实现一些数学运算。
//g++ test5.cpp -std=c++11 -o test5
#include?<functional>
#include?<string>
class?MyCalc
{
public:
? ??float?sum(float?a,?float?b)
? ??{
? ? ? ??return?a + b;
? ? }
? ??float?sub(float?a,?float?b)
? ??{
? ? ? ??return?a - b;
? ? }
};
class?MyClass
{
public:
? ??void?myFunc(std::function<float(float,float)> calcFunc)
? ??{
? ? ? ??float?a =?55;
? ? ? ??float?b =?22;
? ? ? ??float?res = calcFunc(a, b);
? ? ? ??printf("a:%.2f, b:%.2f, res:%.2fn", a, b, res);
? ? }
};
int?main()
{
? ? MyCalc myCalc;
? ? MyClass myClass;
? ??
? ??auto?bindFunc1 =?std::bind(&MyCalc::sum, &myCalc,?std::placeholders::_1,?std::placeholders::_2);
? ? myClass.myFunc(bindFunc1);
? ??
? ??auto?bindFunc2 =?std::bind(&MyCalc::sub, &myCalc,?std::placeholders::_1,?std::placeholders::_2);
? ? myClass.myFunc(bindFunc2);
? ??
? ??return0;
}
示例代码运行结果如下:
3 总结
本篇介绍了C++中bind功能的使用,并通过实际的例里来演示其使用场景。
								
								
								
701