仿函数,适配器

仿函数

  • 仿函数的类别定义中必须重载函数调用operator()
    //仿函数特性:都是需要操作符重载一下(),因为需要让他拥有函数的特性
    greater<int> g;
    cout<< g(1,3) << endl;
    cout<< greater<int>()(1,3) <<endl;//g 相当于 greater<int>()
  • 自定义的仿函数必须重载()

#include <iostream>
#include <vector>
#include <string>
#include<algorithm>
#include<functional>
using namespace std;

template<typename T>
class prints {
public:
    prints(ostream& out):os(out){};
    void operator()(const T& x){
        os << x << " "; 
    }
    std::ostream& os;
};
int main() {
    int buffer[5] = {0,5,9,10,8};
    vector<int> v(buffer, buffer + 5);
    //请注意这里的调用,其实调用的时候是prints<int>(cout)()
    //所以我们需要重载()
    //for_each是把每一个iterator的元素传给prints作为参数
    //为了满足抽象的要求,那么使用仿函数会比较合理
    for_each(v.begin(), v.end(), prints<int>(cout));

    return 0;
}

  • 一个容器的仿函数改变之后是没有可比性的
class Person{};
set<Person,less<Person>> set1,set2;
set<Person,greater<Person>> set3,set4;
//1,2,3,4是不一样的类型
if(set1 == set2)//正确
if(set1 == set3)//错误

仿函数适配器

  • bind1st:有两个参数,一个是二元操作类,一个是被这个二元操作类调用的第一个参数。(bind1st其实就是封装了binder1st的过程)
  • binder1st:这个是一个一元操作类,初始化构造函数把二元操作类和参数保存下来,当调用实际运算事,调用二元操作类。(其实就是指定第一个参数的函数)
#include <iostream>
#include <vector>
#include <string>
#include<algorithm>
#include<functional>
#include<set>
using namespace std;

//not_equal_to的大致
// template struct not_equal_to:
//             binary_function  {

//   // Declaration of the
//   // not equal to operation 
//   bool operator() (const T& x,
//                    const T& y) 
//        const 
//   {
//      return x!=y;
//   }

//   // Type of first parameter
//   typedef T first_argument_type;

//   // Type of second parameter
//   typedef T second_argument_type;

//   // The result is returned
//   // as bool type
//   typedef bool result_type;
// }

//binder1st的实现大致如下:
// template<class T>
// class binder1st:public ...{
// public:
//     binder1st(const T& Func,const typename Func::first_argument& _LEFT):op(Func),value(_LEFT){

//     }
//     result_type operator()(argument_type& _Right) const{
//         return (T(value,_Right));
//     }

// }

int main() {
    //如何看待下面的代码,首先我这里模板的T是为int,所以根据find_if的定义,它的first_argument_type也是等于int
    typename not_equal_to<int>::first_argument_type/*这之前看成int*/ nonZeroElement(0);
    not_equal_to<int> f;
    //多个参数变成一个参数,适配1参数
    //找出一个数组中的首个不等于0的元素
    vector<int> v = {0,0,0,0,0,0,0,502,0,0};
    //vector<int>::iterator it = find_if(v.begin(), v.end(), not_equal_to<int>(0));
    //其中not_equal_to的构造函数不接受参数0,它的()重载也只接受两个参数
    vector<int>::iterator it = find_if(v.begin(), v.end(),
    binder1st<not_equal_to<int>>(f,nonZeroElement));
    //这里的调用其实是调用的binder1st的()重载函数,但是它的重载函数又是调用的T的()重载函数
    vector<int>::iterator it1 = find_if(v.begin(), v.end(),
    bind1st<not_equal_to<int>>(f,nonZeroElement));
    

    cout<<(*it)<<endl;
    cout<<(*it1)<<endl;
    return 0;
}

  • 仿函数适配器bind1st是怎么封装binder1st
template<class _Fn2, class _Ty>
bind1st(const _Fn2& Func,const _Ty& _LEFT){
    typename _Fn2::first_argument_type _Val(_LEFT);
    return (binder1st<_Fn2>(_Func, _Val));
}

那么用话术应该怎么说这个函数呢?
比如bind1st<not_equal_to,int>(not_equal_to(),0);
其实就是这个函数需要两个参数,但是iterator指定的值只给not_equal_to的第一个参数,还需要的一个参数没法给定,所以要给第二个参数的时候就会出现问题。

  • bind2nd适配器的作用和bind1st是相似的,封装的是binder2nd

  • 另外一个仿函数适配器mem_fun/mem_fun_ref(用于适配对象成员函数)
    有一个问题是:

    也就是说for_each的第三个参数需要的是一个全局函数,但是一个对象内部的成员函数是不能满足要求的,而mem_fun就是适配这种类型的。

posted @ 2023-04-04 20:18  铜锣湾陈昊男  阅读(4)  评论(0)    收藏  举报