本篇来介绍了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功能的使用,并通过实际的例里来演示其使用场景。