std::bind()功能学习

转自:https://blog.csdn.net/Jxianxu/article/details/107382049,https://www.jianshu.com/p/af303820fe0f,这个讲的非常好! 

1.介绍

// 绑定到普通函数
template< class F, class... Args >
bind( F&& f, Args&&... args );

std::bind的头文件是 <functional>,bind作用于函数上(包括普通函数,类成员函数等),返回类型为std::function<R(T....)>函数对象(A function object g of unspecified type T),这个类里面实现了operator()操作符,使得这个对象能像函数一样能使用()调用。

std::bind返回一个函数对象function类型,主要看传入的函数F的参数和返回类型,参数要么被绑定到,要么被绑定到placeholders(占位符,如_1, _2, ..., _n)。

主要作用:

  • 将可调用对象和其参数绑定成一个仿函数
  • 只绑定部分参数,减少可调用对象传入的参数。

2.绑定普通函数

double callableFunc (double x, double y) {return x/y;}
auto NewCallable = std::bind (callableFunc, std::placeholders::_1,2);  
std::cout << NewCallable (10) << '\n';                        // 输出5
  • bind的第一个参数是函数名,普通函数做实参时,会隐式转换成函数指针。因此std::bind(callableFunc,_1,2)等价于std::bind (&callableFunc,_1,2);
  • _1表示占位符,位于<functional>中,std::placeholders::_1;
  • 第一个参数被占位符占用,表示这个参数以调用时传入的参数为准,在这里调用NewCallable时,给它传入了10,其实就想到于调用callableFunc(10,2);

3.绑定类对象的成员函数

class Base
{
    void display_sum(int a1, int a2)
    {
        std::cout << a1 + a2 << '\n';
    }
    int m_data = 30;
};
int main() 
{
    Base base;
    auto newiFunc = std::bind(&Base::display_sum, &base, 100, std::placeholders::_1);
    f(20); // should out put 120. 
}
  • bind绑定类成员函数时,第一个参数表示对象的成员函数的指针,第二个参数表示对象的地址。
  • 必须显式地指定&Base::diplay_sum,因为编译器不会将对象的成员函数隐式转换成函数指针,所以必须在Base::display_sum前添加&;
  • 使用对象成员函数的指针时,必须要知道该指针属于哪个对象,因此第二个参数为对象的地址 &base;

// 还可以绑定到类的数据成员,不太了解这是什么用法,之后有用到再说。

4.绑定引用参数

如果函数声明中的形参类型是引用,那么在bind时可以通过ref()函数来绑定参数。

传入bind的参数要加std::ref,会引用传参,可以在bind调用函数时修改参数的内容。

5.语法示例

好处:

  1. 函数对象操作方式和函数几乎一致,不会带来新的语法难度。 
  2. 函数对象可以预设函数的部分参数,更加灵活。
  3. 函数对象可以绑定到类的成员函数。

注意,函数对象和函数指针是不一样的,两个格式声明不同:

//函数指针:
void (*) (int, const std::string&); //返回类型(*)(参数类型列表)

//函数对象:
std::function<void(int)> f_int  //std::function<返回类型(参数类型列表)>

样例case,很厉害:

#include<iostream>
#include<atomic>
#include<thread>
#include<vector>
#include<atomic>
#include <functional>
using namespace std;
 
// g++ --std=c++11 ./seqid.cpp -o seqid -lpthread 
class T
{
public:
  static bool big_than(int a, int b) { return a > b; }
  bool mem_big_than(int a, int b) { return a > b; }
};

int for_each_array(std::vector<int>& vec, std::function<bool(int)> f) {// 注意到这个函数对象f只有一个int类型的形参
  int count = 0;
  for (auto iter = vec.begin(); iter != vec.end(); ++iter) {
    if (f(*iter)) ++count;
  }
  return count;
}

int main() {
  //绑定到类的静态函数
  auto f = std::bind(&T::big_than, std::placeholders::_1, 10);
  std::vector<int> vec = {100,100,300,2,1,3};
  int res = for_each_array(vec, f);
  cout<<res<<endl;
  
  //绑定到类的普通成员函数
  T t;
  auto f2 = std::bind(&T::mem_big_than, &t, std::placeholders::_1, 10);
  res = for_each_array(vec, f2);
   cout<<res<<endl;
  return 0;
}
View Code

 case2,绑定类对象作为函数形参:

struct Person{
    void pprint(){cout<<"Person.\n";}
};

typedef std::function<void(const std::string &name)> callback;
void setMyFunc(callback call){
    call("hh");
}

void preFunc(Person* p,const std::string &name){// 固定类参数到这个类型
    p->pprint();
    cout<<name<<" ok\n";
}

int main() { 
    Person p(5);
    auto myfunc = std::bind(preFunc,&p,std::placeholders::_1);
    setMyFunc(myfunc);
}
View Code

6.应用场景  

回调处理函数。某个处理函数中,遇到某种情况,可能需要在另一个类执行某些操作,且这些操作的参数依赖于处理函数中的变量。如下所示:

T *obj = get_obj();
int param = argv[0];
int ret = deal_with_param(param);
// 在执行deal_with_param时,发生了错误。需要在类T中做某些通知操作。
// 这个通知的动作依赖于当下的参数param。这里的bind就起到了回调的作用。
if (ret) { obj->failed(std::bind(some_func, std::placeholders::_1, param)); }

7.自己定义function类型

class Base
{
    public:
    void display_sum(int a1, int a2)
    {
        std::cout << a1 + a2 << '\n';
    }
};

int main() { 
    Base base;
    // 这样是不对的,因为已经display_sum绑定到两个int了,参数已固定,f是没有形参的了
    std::function<void(int, int)> f = std::bind(&Base::display_sum, &base,1,2);
    // 正确的写法
    std::function<void()> f = std::bind(&Base::display_sum, &base,1,2);
    f();// 输出3

    // 或者使用占位符,延迟传参
    std::function<void(int)> f2 = std::bind(&Base::display_sum, &base,1,std::placeholders::_1);
    f2(10); // 输出11
    return 0;
}

 

posted @ 2022-09-24 15:50  lypbendlf  阅读(161)  评论(0编辑  收藏  举报