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, 10, 2); //返回一个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, 2); //my_divide的第2个参数绑定为2 cout << fn2(10) << endl; // 输出5 //cout << fn2(10, 3) << endl; // 输出仍然为5! auto fn3 = bind(my_divide, _2, _1); cout << fn3(10, 2) << endl; //输出:0.2。注意10为第1个参数,被绑到_1的位置,2绑到_2的位置 auto fn4 = bind<int>(my_divide, _1, _2); //指定返回值为int型 cout << fn4(10, 3) << endl; //2、绑定类的成员 MyPair mp{10, 2}; //注意,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; //10 ftor_memdata() = 100; //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; //2 ftor_memdata2(mp) = 50; //传mp的引用 cout << mp.b << endl; //由于按引用传递,b的值被改! cout << ftor_memdata2(mp) << endl; return 0; }
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, 2); out1(1); //输出:1, 2 auto out2 = bind(output, 2, _1); out2(1); //输出:2, 1 auto out3 = bind(output, 2, _2); out3(1, 3); //输出2, 3(注意,第1个参数被默认的2取代了) //out3(1); //error, 调用时需给出第2个参数 auto out4 = bind(output, 2, _2); out4(1, 3); //输出2, 3 //out4(1); //error, 调用时需给出第2个参数 auto out5 = bind(output, _2, _1); out5(1, 3); //输出3, 1(第1个实参对应_1,第2个实参对应_2) vector<int> v{15, 37, 94, 50, 73, 58, 28, 98}; //通过bind2nd绑定 int n = count_if(v.begin(), v.end(), not1(bind2nd(less<int>(), 50))); cout <<"n = " << n << endl; //5(大于等于50的元素个数) //通过bind绑定 auto fn = bind(less<int>(), _1, 50); cout << count_if(v.begin(), v.end(), fn) << endl; //3,小于50的元素个数 cout << count_if(v.begin(), v.end(), bind(less<int>(), _1, 50)) << endl; //3 //组合使用bind //查找(50,73]之间的元素个数 auto f = bind(logical_and<bool>(), bind(greater<int>(), _1, 50), bind(less_equal<int>(), _1, 73)); cout << count_if(v.begin(), v.end(), f) << endl; //2 return 0; }