第11课 std::bind和std::function(2)_std::bind绑定器

时间:2025-04-23 22:36:13

1. 温故知新:std::bind1st和std::bind2nd

(1)bind1st、bind2nd首先它们都是函数模板,用于将参数绑定到可调用对象(如函数、仿函数等)的第1个或第2个参数上

(2)函数的返回值是一个函数对象。它用于包装和改造传入的函数(或仿函数),并形成一个新的仿函数对象(是一个可调用对象)

(3)与旧的可调用对象相比,新的仿函数对象参数个数少了1个。(相当于给少掉的那个参数一个默认的值

2. std::bind绑定器

(1)首先,std::bind也是一个函数模板,返回值是一个仿函数,也是可调用对象。它的作用与bind1st和bind2st类似,是这两个函数的加强版。但极大地提高了灵活性,可以完全替代bind1st和bind2nd。

(2)bind的作用主要就是将可调用对象变成std::function对象(即仿函数对象),主要体现在两个方面。

  ①将多元的可调用对象与其参数一起绑定成一个仿函数对象。

  ②将多元(设参数个数为n)的可调用对象转成一元或(n-1)元的可调用对象,即只绑定部分参数

(3)std::bind可以绑定的对象(注意bind的返回值是仿函数)

  ①普通函数(functions);

  ②函数对象(仿函数,function objects);

  ③类的成员函数(member functions。注意:_1必须是某个对象的地址

  ④类的数据成员(data members注意:_1必须是某个对象的地址

【编程实验】std::bind初探

#include <iostream>
#include <vector>
#include <functional> // for std::bind
#include <typeinfo> using namespace std::placeholders; //让_1, _2, _3,...可见!
using namespace std; //除法函数:x/y
double my_divide(double x, double y)
{
return x / y;
} struct MyPair
{
double a, b;
MyPair(int a, int b):a(a), b(b)
{ cout << "MyPair(int a, int b)" << endl;
}
//注意成员函数的第1个参数是this!!!
double mutiply(){return a * b;}
}; int main()
{
//1、绑定函数
auto fn1 = bind(my_divide, , ); //返回一个std::function类型的仿函数
//function<double(void)> fn1 = bind(my_divide, 10, 2); //绑定完,fn1是无参,所以为void
//cout << typeid(fn1).name() << endl;
cout << fn1() << endl; auto fn2 = bind(my_divide, _1, ); //my_divide的第2个参数绑定为2
cout << fn2() << endl; // 输出5
//cout << fn2(10, 3) << endl; // 输出仍然为5! auto fn3 = bind(my_divide, _2, _1);
cout << fn3(, ) << endl; //输出:0.2。注意10为第1个参数,被绑到_1的位置,2绑到_2的位置 auto fn4 = bind<int>(my_divide, _1, _2); //指定返回值为int型
cout << fn4(, ) << endl; //2、绑定类的成员
MyPair mp{, }; //注意,mp是个聚合对象,可用{}直接初始化(虽无2个参数的构造函数)。 auto ftor_memfn = bind(&MyPair::mutiply, _1); //成员函数,其实有个this指针,须放入_1
cout << ftor_memfn(mp) << endl; //20,传入mp对象的地址(这里传的是引用) auto ftor_memdata = bind(&MyPair::a, mp); //传mp对象的副本,
//auto ftor_memdata = bind(&MyPair::a, &mp); //传mp的地址
cout << ftor_memdata() << endl; //
ftor_memdata() = ; //mp副本的a值被改为100
cout << mp.a << endl; //10,mp本身的a值未被改变,仍为10
cout << ftor_memdata() << endl; auto ftor_memdata2 = bind(&MyPair::b, _1);
cout << ftor_memdata2(mp) << endl; //
ftor_memdata2(mp) = ; //传mp的引用
cout << mp.b << endl; //由于按引用传递,b的值被改!
cout << ftor_memdata2(mp) << endl; return ;
}

3. 使用std::bind的注意事项

(1)bind预先绑定的参数需要传具体的变量或值进去,对于预先绑定的参数是按值传递的

(2)对于不事先绑定的参数,需要传std::placeholders进去,从_1开始,依次递增。注意,对于placeholder是按引用传递的。

(3)通过placeholder可以改变传参的顺序。同时如果放置了placeholder_x的占位符,当调用时就必须给足至少x个实参

(4)bind的返回值是可调用实体,可以直接赋值给std::function对象

(5)对于绑定的指针、引用类型的参数,使用者需要保证在可调用对象调用之前,这些参数是可用的。

【编程实验】placeholder、组合使用bind函数

#include <iostream>
#include <vector>
#include <algorithm> //for count_if
#include <functional> // for std::bind using namespace std;
using namespace std::placeholders; void output(int x, int y)
{
cout << x << ", " << y << endl;
} int main()
{
auto out1 = bind(output, _1, );
out1(); //输出:1, 2 auto out2 = bind(output, , _1);
out2(); //输出:2, 1 auto out3 = bind(output, , _2);
out3(, ); //输出2, 3(注意,第1个参数被默认的2取代了)
//out3(1); //error, 调用时需给出第2个参数 auto out4 = bind(output, , _2);
out4(, ); //输出2, 3
//out4(1); //error, 调用时需给出第2个参数 auto out5 = bind(output, _2, _1);
out5(, ); //输出3, 1(第1个实参对应_1,第2个实参对应_2) vector<int> v{, , , , , , , }; //通过bind2nd绑定
int n = count_if(v.begin(), v.end(), not1(bind2nd(less<int>(), )));
cout <<"n = " << n << endl; //5(大于等于50的元素个数) //通过bind绑定
auto fn = bind(less<int>(), _1, );
cout << count_if(v.begin(), v.end(), fn) << endl; //3,小于50的元素个数
cout << count_if(v.begin(), v.end(), bind(less<int>(), _1, )) << endl; //3 //组合使用bind
//查找(50,73]之间的元素个数
auto f = bind(logical_and<bool>(), bind(greater<int>(), _1, ), bind(less_equal<int>(), _1, ));
cout << count_if(v.begin(), v.end(), f) << endl; // return ;
}