bind1st和bind2nd

来源:互联网 发布:cn是哪个国家的域名 编辑:程序博客网 时间:2024/05/20 05:09

自己学习的笔记,文章转载于http://imcc.blogbus.com/logs/162062257.html

关于bind1st和bind2nd,这是两个在C++泛型(主要在STL、模板)很常用的两个函数,从这两个函数的名字就可以知道,他们的意义就是邦定(bind)某个函数的第一个参数(1st)或者第二个参数(2nd)。我们常常在STL算法中应用函数指针或者函数对象对算法进行自己定义,例如,我们用一个printall()函数来对for_each()算法进行自定义,输出某个容器中的所有数据:
using namespace std;void printall(int n){cout<}int main(){vector v = {63,47,93,75};// 打印容器中的全部数据for_each(v.begin(),v.end(),printall);return 0;}
通过将函数指针printall转递给for_each算法,它就会以容器中的数据为参数调用这个函数,完成所有数据的输出。这是最简单的最常用的形式。但是这种方式有一个缺点,就是不够通用灵活。例如,如我们想只是输出及格(>60)分数,我们就不得不另外写一个printpass函数来完成,而如果我们还有更多的变化,例如输出优秀(>85)、或者是差生的分数(<40),等等,情况有很多,采用这种方式,我们不得不为每一种情况实现一个专门的函数。这显然不符合泛型编程的思想(通用,一定要通用)。于是,bind1st和bind2nd也就派上了用场。如果某个函数或函数对象调用需要两个参数,bind1st会绑定我们在调用bind1st的函数调用表达式中给出的参数为函数对象的第一个参数,而形成一个新的函数对象,也就是将一个二元(两个参数)函数对象的第一个参数固定下来,而形成一个新的只需要一个参数的一元函数对象,而将这个新的函数对象应用到算法时,相当于只有一个参数了(第一个参数已经被绑定),这时候情况就跟上面的例子完全相同了。例如:
void print(int standard,int n) // 创建一个需要两个参数的函数{if(n>=standard)cout<}int main(){vector v = {63,47,93,75};// 打印容器中大于60的数据for_each(v.begin(),v.end(),bind1st(ptr_fun(print),60)); // 这里,ptr_fun的作用是将一个函数指针构造成一个函数对象(你也可以直接使用函数对象),而bind1st就是绑定这个函数对象的第一个参数为60,也就是standard为60,整个函数变为print(60, int n),只有一个参数了,这是完全跟上面的例子相同了。return 0;}
bind2nd的原理是一样的,只不过是为了邦定函数的第二个参数。而在新标准C++11中,还有bind函数,可以帮定更多参数。这些函数的使用是有点复杂,多加练习,熟悉后就好了。

一些调用bind1st或bind2nd例子:

int a[] = {1, 2, 100, 200};std::vector< int> arr(a, a + 4);// 移除所有小于100的元素arr.erase( std::remove_if( arr.begin(),  arr.end(),    std::bind2nd( std::less< int>(), 100)), arr.end());
// 移除所有大于100的元素arr.erase( std::remove_if( arr.begin(),  arr.end(),    std::bind1st( std::less< int>(), 100)), arr.end());
// 移除所有大于100的元素arr.erase( std::remove_if( arr.begin(),  arr.end(),    std::bind2nd( std::greater< int>(), 100)), arr.end());
// 移除所有小于等于100的元素arr.erase( std::remove_if( arr.begin(),  arr.end(),    std::not1(std::bind2nd( std::greater< int>(), 100))), arr.end());
// trim from beginstatic inline wstring &ltrim(wstring &s) {    s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(std::isspace))));    return s;}
// trim from endstatic inline wstring &rtrim(wstring &s) {    s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());    return s;}

ptr_fun是将一个普通的函数适配成一个仿函数(functor), 添加上argument_type和result type等类型,它的定义如下:

template<class _Arg1,class _Arg2,class _Result> inline      pointer_to_binary_function<_Arg1, _Arg2, _Result,    _Result(__clrcall *)(_Arg1, _Arg2)>              ptr_fun(_Result (__clrcall *_Left)(_Arg1, _Arg2))      {    // return pointer_to_binary_function functor adapter      return (pointer_to_binary_function<_Arg1, _Arg2, _Result,          _Result (__clrcall *)(_Arg1, _Arg2)>(_Left));      }  

下面的例子就是说明了使用ptr_fun将普通函数(两个参数, 如果有多个参数, 要改用boost::bind)适配成bind1st或bind2nd**能够使用的functor,否则对bind1st或bind2nd直接绑定普通函数,则编译出错。**

#include <algorithm>    #include <functional>    #include <iostream>    using namespace std;    int sum(int arg1, int arg2)    {        std::cout<< "arg1 = " << arg1 << std::endl;        std::cout<< "arg2 = " << arg2 << std::endl;        int sum = arg1 + arg2;        std::cout << "sum = " << sum << std::endl;        return sum;    }  int main(int argc, char *argv[], char *env[])  {        bind1st(ptr_fun(sum), 1)(2);        // the same as sum(1,2)        bind2nd(ptr_fun(sum), 1)(2);        // the same as sum(2,1)        return 0;  }  
0 0