四. bind绑定的对象
  我们上面看到lambda表达式可以很好地解决标准库有些函数的谓词问题,现在我们想问的问题是,如果不想用lambda来实现谓词的转换,我只想用函数,那么怎么办呢?标准库提供了一个很好的办法,那是bind函数(C++11 Feature)。(定义在头文件functional里面)。
  简单的来说,bind可以把一些固定的参数和函数绑定,然后调用函数的时候相当于被绑定的参数不用填了,相当于减少了传入参数的数量,比如上面的例子我们可以这么改。
  1 bool findMin(const int &a, const int &value)
  2 {
  3     return a >= value;
  4 }
  5 segFloorIndex = find_if(nums.begin(), nums.end(), bind(findMin, _1, floorSize));
  6 segCeilIndex = find_if(nums.begin(), nums.end(), bind(findMin, _1, ceilSize));
  其中_1(类似的还有_2,_3....)这个东西为占位符(有点像汇编的那个,定义在std的placeholders的作用域),表示的是外面的可以传入的参数,参数从左到右依次填入_1,_2...中(比如如果有调用对象G的定义为auto G= bind(f, _2, a, _1 ),调用G(x,y)实际上是f(Y,a,x ),用这个拿来交换参数位置)。
  有些参数bind不能直接绑定(比如万恶的输入输出流不允许拷贝),那用标准库的ref函数来得到这个对象的引用可以了(cref是得到常量引用,这两个都在functional的头文件中)。
  五. 重载了函数调用符的类
  C++的类厉害的地方之一是可以重载函数运算,是retType operator( )(parameter...){ }的形式,这种重载了函数调用符的类可以直接让我们用类名来实现函数的功能,比如:
  1 class FunctonalClass
  2 {
  3 public:
  4     bool operator()(const int &a, const int &value)
  5     {
  6         return a >= value;
  7     }
  8 };
  当然了上面的这个例子我是故意写成这样的,其实和lambda调用形式长得很像,其实lambda是相当于重载了函数调用符的类去掉了类名而已,事实上lamba也是在做类的事情,比如在3的lambda其实是这样展开的:
  1 class AnonymityFunctional
  2 {
  3 public:
  4     AnonymityFunctional(const int &v) :value(v) { }
  5     bool operator()(const int &a) const { return a >= value; }
  6 private:
  7     const int &value;
  8 };
  调用形式:
  segFloorIndex = find_if(nums.begin(), nums.end(), AnonymityFunctional(floorSize));
  segCeilIndex = find_if(nums.begin(), nums.end(), AnonymityFunctional(ceilSize));
  lambda表达式产生的类不含默认构造函数,赋值运算符和默认析构函数,它是否含有默认的拷贝和移动函数那要视捕获的数据成员来定。
  事实上这种函数对象再functional里面一大把,看看标准库知道了,标准库的函数对象一般为类模板,比如greator<T>。
  利用std::function创建可调用对象的集合
  上面说了5种可调用对象,有时候我们想实现某些设计模式的时候,我们想用一个统一接口来调用这些对象,实现可调用对象表,但是这些可调用对象本质上类型都是不一样的,如何把他们统一起来呢?答案是使用标准库模板function<T>,
  简单的,我们可以把function的统一接口:
  std::function<bool(const int &)>
  这个时候,可以添加形如返回值的bool,形参为const int&的对象进去了,无论是lambda还是函数指针还是类调用对象:
  1 bool fcn(const int &a){ return a; }
  2
  3 class FunctionTest
  4 {
  5 public:
  6     FunctionTest() = default;
  7
  8     bool getWhat(const int &a)const { return true; }
  9     bool getS()const { return true; }
  10 };
  11
  12 std::function<bool(const int &)> f1 = [](const int &a) { return a ; };
  13 std::function<bool(const int &)> f2 = Test();
  14 std::function<bool(const int &)> f3 = fcn;
  常见的是把一些函数放进map里面,那样我们可以根据关键字来调用对象了,非常方便。不过需要注意的是,如果函数是重载过的,那我们不能直接塞函数名进去了(会产生二义性),这个时候要自己创建要放入函数的函数指针,再创建function。
  1 bool fcn() { return true; }
  2 bool fcn(const int &a){ return a; }
  3
  4 bool(*pfcn)(const int &) = fcn;
  5 std::function<bool(const int &)> f3 = pfcn;
  关于类成员函数指针转换为可调用对象的问题:
  说实话这个指针方法很少用到(不过在Qt上可以用这个来实现信号和槽的绑定,写的时候比用SIGNAL和SLOT好,当然这种写法信号和槽不能有函数重载),类成员函数指针可以用来指向类的非静态函数(也是类成员指针使用的时候一定要绑定类对象),因为成员函数指针必须用*.或者是->*先给类解引用了才可以使用,所以本质上成员函数指针不是可调用对象,但是我们仍然可以用function或者bind来是它成为可调用对象。
  不过说实话这个东西确实有点偏,先扯一下用法把,假设一个类里面有一个类:
  1 class FunctionTest
  2 {
  3 public:
  4     FunctionTest() = default;
  5
  6     bool getWhat(const int &a)const { return true; }
  7     bool getS()const { return true; }
  8 };
  然后我们这样定义一个成员函数指针,让它指向getWhat
  1 FunctionTest haha, *phaha = &haha;
  2
  3 bool (FunctionTest::*pf)(const int &) const;//先定义一个指针
  4 pf = &FunctionTest::getWhat;//指针指向类的什么函数
  5
  6 auto ret = (haha.*pf)(floorSize);
  7 auto ret1 = (phaha->*pf)(ceilSize);
  *.和->*是用来定义指向成员的,*.给对象用,->*给指向对象的指针用,这个很好理解(这里我只是用来演示了一下找成员函数,其实找成员也是这样找的)。
  当然了上面的写法是为了应付有函数重载的情况,如果没有函数重载,那么auto肯定是好的拉~
  auto pf = &FunctionTest::getWhat;
  好了扯了那么多那怎么用fcuntion来生成成员函数指针的可调用对象呢?很简单,直接:
  std::function<bool(const FunctionTest *, const int &)> f4(&FunctionTest::getWhat);
  这里我们发现了要生成成员函数的可调用对象必须带对象,所以生成的可调用对象都必须带类的对象,这很符合成员函数指针的要求——必须绑定对象,事实上,当我们使用这样的可调用对象的时候,相当于把this指针先传给第一个参数了,所以这个function对象本质上是需要两个参数的!不能用于find_if。
  当然了,生成一个这样的的调用对象,除了用function,还可以用标准库的另一个函数:mem_fn
  auto f = std::mem_fn(&FunctionTest::getWhat);
  生成的可调用对象f和function类似,这个调用对象f也是不能用于find_if,因为他一定要传this进去,而getWhat本身是一元谓词,f4直接变二元了。