1、bind1st和bind2end
bind1st和bind2end是C++中的函数绑定器,它可以将一个变量绑定至一个二元函数对象,从而获得一个一元函数对象。使用需要包含头文件<functional>
比如我们使用find_if()查找容器中大于100的元素,使用函数和函数对象的方法是如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
bool GreaterThan(const int& i)
{
return i > 100;
}
class CGreaterThan
{
public:
bool operator()(const int&i)
{
return i > 100;
}
};
int main()
{
vector<int> v = list_of(5) (2) (101) (3);
auto iter = find_if(v.begin(), v.end(), /*GreaterThan*/CGreaterThan());
if (iter != v.end())
cout << *iter << endl;
return 0;
}
而使用函数绑定器的话就不用我们自定义函数或函数对象,如下所示:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <functional> int main() { vector<int> v = list_of(5) (2) (101) (3); int x = 100; auto iter = find_if(v.begin(), v.end(), bind2nd(greater<int>(), x)); if (iter != v.end()) cout << *iter << endl; return 0; }
上面的bind2nd()将值100绑定到二元谓词greater<int>()的第二个参数,相当于将greater<int>()的第二个参数直接替换成了100,如果使用bind1st()的话就是将值绑定到第一个参数。
not1和not2可以用来做否定值(not1是否定返回值是单目的函数,std中还有not2它是否定返回值是双目的函数),如以下就是获得小于等于100的元素:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
int main()
{
vector<int> v = list_of(5) (2) (101) (3);
auto iter = find_if(v.begin(), v.end(), not1(bind2nd(greater<int>(), 100)));
if (iter != v.end())
cout << *iter << endl;
return 0;
}
2、bind
boost中的bind是bind1st/bind2nd的增强版,它也会返回一个函数对象,可以通过function来保存和调用。bind()的第一个参数必须是一个可调用对象,比如函数、函数指针、函数对象,之后它最多接受九个参数。占位符用来表示使用哪一个参数。boost中的bind位于头文件"boost/bind.hpp"中,c++11中已经增加了bind,头文件为<functional>,使用占位符的话需要其所在的命名空间:using namespace std::placeholders;
①、绑定普通函数
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> using namespace std; #include "boost/bind.hpp" #include "boostfunction.hpp" void func1p(int num) { cout << num << endl; } void func3p(int a, int b, int c) { cout << a << endl << b << endl << c << endl; } int main() { int n = -1; //绑定变量n到func1p的参数:不用再传参; boost::function<void()> fun = boost::bind(func1p, n); fun(); //输出-1 int x = 0, y = 5, z = 10; //绑定变量x到func3p的第一个参数:第一个参数直接使用x,不用传参;第二个参数使用实参列表的第一个参数;第三个参数使用实参列表的第二个参数 boost::function<void(int, int)> func = boost::bind(func3p, x, _1, _2); func(y, z); //输出0, 5, 10 //绑定变量y到func3p的第二个参数:第二个参数直接使用y,不用传参;第一个参数使用实参列表的第一个参数;第三个参数使用实参列表的第二个参数 func = boost::bind(func3p, _1, y, _2); func(x, z); //输出0, 5, 10 //绑定变量z到func3p的第三个参数:第三个参数直接使用z,不用传参;第一个参数使用实参列表的第一个参数;第二个参数使用实参列表的第二个参数 func = boost::bind(func3p, _1, _2, z); func(x, y); //输出0, 5, 10 return 0; }
下面是使用bind绑定普通函数的一个使用示例。
我们想要利用count_if()算法来获得容器中元素长度小于5的元素的个数,如果是使用普通函数来作为count_if的谓词的话只能在函数中写死长度,因为count_if中谓词函数的参数只能有一个,代码如下所示:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
bool ShorterThanFun(const string& str) { return str.length() < 5; } int main() { vector<string> myVector = list_of("c++") ("c#") ("python"); int count = count_if(myVector.begin(), myVector.end(), ShorterThanFun); return 0; }
可以使用bind来绑定长度到谓词函数的第二个参数,从而获得一个参数的谓词函数,但谓词函数实际上是带两个参数:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include "boost/bind.hpp" bool ShorterThanFun(const string& str, int len) { return str.length() < len; } int main() { vector<string> myVector = list_of("c++") ("c#") ("python"); int len = 5; int count = count_if(myVector.begin(), myVector.end(), bind(ShorterThanFun, _1, len)); return 0; }
②、绑定函数指针
bind绑定函数指针与绑定普通函数方法相同。
③、绑定类的成员函数
使用情景1:
bind绑定类的public成员函数用来配合STL算法来操作容器中的对象,以下是使用bind与不使用bind完成对容器for_each()操作的比较:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include "boost/bind.hpp" class CMyClass { public: void print() { cout << m_Value1 << ", " << m_Value2 << endl; } private: int m_Value1 = 0, m_Value2 = 0; }; void Print(CMyClass& c) { c.print(); } int main() { vector<CMyClass> v(10); for_each(v.begin(), v.end(), /*Print*/boost::bind(&CMyClass::print, _1)); return 0; }
使用情景2:
bind绑定类的成员函数后可以将类的成员函数当做普通函数来使用,即bind配合funcion绑定指定对象的成员函数后可以通过该function对象调用指定对象的成员函数。与情景1不同的是,这里绑定类的成员函数的时候bind的第二个参数应该传入成员函数所在类的实例对象或其地址:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class CTest { public: void call_back_func(int i) { cout << i << endl; } }; class CTestClass { public: CTestClass(int i) :m_iNum(i) {} public: template<typename T> void SetCallBack(T f) { m_fFun = f; } void run() { if (m_fFun) m_fFun(m_iNum); } private: function<void(int)> m_fFun; int m_iNum; }; int main() { CTestClass dc(10); CTest t; dc.SetCallBack(boost::bind(&CTest::call_back_func, t, _1)); dc.run(); return 0; }
④、绑定类的成员变量
bind还可以绑定类的public成员函数,同样配合STL算法来操作容器中的元素,以下是使用bind与不使用bind完成对容器transform()操作的比较,可以看到,如果我们在容器的谓词函数中只是调用容器元素的成员函数的话则可以使用bind绑定类的成员函数,这样更加方便:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include "boost/bind.hpp" class CPoint { public: int x = -1; int y = -1; }; int assign(CPoint point) { return point.x; } int main() { vector<CPoint> inputV(10); vector<int> outputV(10); transform(inputV.begin(), inputV.end(), outputV.begin(), /*assign*/bind(&CPoint::x, _1)); for (auto iter = outputV.begin(); iter != outputV.end(); iter++) cout << *iter << endl; return 0; }
⑤、绑定函数对象
bind绑定函数对象的时候需要在被绑定类中使用typedef来定义operator()返回值类型为result_type,否则在bind的时候还需使用<type>来指定类型。
下面为使用count_if()算法来查找容器中元素长度小于5的个数,而count_if()使用的仿函数类型中只有一个参数,可以使用两种方法来实现长度参数的传递:一种是将长度作为仿函数的构造函数的参数传入,一种是使用bind来获得一个参数的仿函数:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include "boost/bind.hpp" class CLengthShorterThan { public: CLengthShorterThan(int len):m_len(len){} bool operator()(const string& str) { return str.length() < m_len; } private: int m_len; }; class CLenShorterThan { public: bool operator() (const string& str, int len) { return str.length() < len; } typedef bool result_type; }; int main() { vector<string> myVector = list_of("c++") ("c#") ("python"); int len = 5; int count = count_if(myVector.begin(), myVector.end(), /*CLengthShorterThan(len)*/bind(CLenShorterThan(), _1, len)); return 0; }
bind也可以绑定预定义的函数对象,如less<>、greater<>等。还可以使用BOOST_AUTO来存储bind表达式的结果,即保存bind返回的函数对象,以便使用。function库也可以存储bind表达式的结果。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include "boost/bind.hpp"
#include "boost/typeof/typeof.hpp"
int main()
{
BOOST_AUTO(funObj, bind(greater<int>(), _1, _2));
assert(funObj(2, 1));
return 0;
}
3、bind配合使用ref
bind采用拷贝的方式存储绑定的对象或参数,如下为使用count_if()算法来获得容器中元素长度小于5的元素个数,bind绑定len到仿函数的第二个参数,len参数是值传递,即使在operator()中被声明为了int&:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include "boost/bind.hpp" class CLenShorterThan { public: bool operator() (const string& str, int& len) { int iLen = len; len = 0; return str.length() < iLen; } typedef bool result_type; }; int main() { vector<string> myVector = list_of("c++") ("c#") ("python"); int len = 5; int count = count_if(myVector.begin(), myVector.end(), bind(CLenShorterThan(), _1, len)); cout << len << endl; //输出为5 return 0; }
可以给bind绑定的参数传入ref()引用包装类型,使参数为引用传递:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include "boost/bind.hpp"
class CLenShorterThan
{
public:
bool operator() (const string& str, int& len)
{
int iLen = len;
len = 0;
return str.length() < iLen;
}
typedef bool result_type;
};
int main()
{
vector<string> myVector = list_of("c++") ("c#") ("python");
int len = 5;
int count = count_if(myVector.begin(), myVector.end(), bind(CLenShorterThan(), _1, ref(len)));
cout << len << endl; //输出为0
return 0;
}