bind

概念

  • boost中的bind是bind1st/bind2nd的增强版,它也会返回一个函数对象,可以通过function来保存和调用。
  • bind()的第一个参数必须是一个可调用对象,比如函数、函数指针、函数对象,之后它最多接受九个参数。
  • 占位符用来表示使用哪一个参数。boost中的bind位于头文件"boost/bind.hpp"中,
  • c++11中已经增加了bind,头文件为,使用占位符的话需要其所在的命名空间:using namespace std::placeholders;

使用

绑定普通函数

#include <iostream>
using namespace std;

#include "boost/bind.hpp"
#include "boost\function.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;
}
#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;
}

绑定类的成员函数

#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;
}

绑定类的成员变量

#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;
}

绑定函数对象

  • 下面为使用count_if()算法来查找容器中元素长度小于5的个数,而count_if()使用的仿函数类型中只有一个参数,可以使用两种方法来实现长度参数的传递:
  • 一种是将长度作为仿函数的构造函数的参数传入,
  • 一种是使用bind来获得一个参数的仿函数:
#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配合使用ref

  • bind采用拷贝的方式存储绑定的对象或参数,
  • 如下为使用count_if()算法来获得容器中元素长度小于5的元素个数,bind绑定len到仿函数的第二个参数,len参数是值传递,即使在operator()中被声明为了int&:
  • 可以给bind绑定的参数传入ref()引用包装类型,使参数为引用传递:
#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;
}

使用shared_ptr做线程参数

#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <string>


using namespace std;


class A
{
public:
        virtual void out() {cout << "A::out();" << endl;}
};

class B : public A
{
public:
    B() {cout << "construct B;" << endl;}
    virtual void out() { cout << "B::out();" << endl; }

    ~B(){ cout << "destroy B;" << endl;}
};



/*
  fun2 可以接收任何A类以及从A派生的类的shared_ptr对象.
  这样做,勉强也可算是支持任意类型了,因为只要传递的参数是从A派生即可.
*/
void* fun2(boost::shared_ptr<A> pa)
{
    // 不再需要任何转换,直接访问其子类的虚方法了.

    pa->out();
    sleep(10);
}

void fun()
{
    /*
       代码确实很简洁了.
    */
    boost::shared_ptr<B> pb(new B());
    boost::thread bthread(boost::bind(fun2, pb));

    bthread.join();
}

int main()
{
    fun();
    cout << "FINISH" << endl;
}