• 谓词、内建函数对象、函数对象适配器


    一、谓词概念

    谓词是指普通函数或重载的operator()返回值是bool类型的函数对象(仿函数)。如果operator接收一个参数,那么叫做一元谓词,如果接收两个参数,那么叫做二元谓词,谓词可作为一个判断式。

    二、内建函数对象

    STL内建了一些函数对象,分为:算数类函数对象,关系运算类函数对象,逻辑运算类仿函数。这些仿函数所产生的对象,用法和一般函数完全相同,当然我们还可以产生无名的临时对象来履行函数功能,使用内建函数对象,需要引入头文件#include<functional>

    6个算数类函数对象,除了negate是一元运算,其他都是二元运算。

    6个关系运算类函数对象,每一种都是二元运算。

    逻辑运算类仿函数,not为一元运算,其余为二元运算。

    案例(以plus为例):

    #define _CRT_SECURE_NO_WARNINGS
    #include <iostream>
    #include <functional>
    using namespace std;
    
    void test01()
    {
        //使用内建函数对象声明一个对象
        plus<int> myplus;
        cout << myplus(10, 20) << endl;//30
        //使用匿名临时对象
        cout << plus<int>()(5, 6) << endl;//11
    }
    
    int main(void)
    {
        test01();
        return 0;
    }

    三、函数对象适配器

    函数对象适配器是完成一些配接工作,这些配接包括绑定(bind),否定(negate),以及一对一般函数或成员函数的修饰,使其成为函数对象,重点掌握函数对象适配器(红色字体):

    bind1st:将参数绑定为函数对象的第一个参数

    bind2nd:将参数绑定为函数对象的第二个参数

    not1:对一元函数对象取反

    not2:对二元函数对象取反

    ptr_fun:将普通函数修饰成函数对象

    mem_fun:修饰成员函数

    mem_fun_ref:修饰成员函数

    1、绑定适配器:bind1st、bind2nd

    bind1st和bind2nd函数把一个二元函数对象绑定成为一个一元函数对象。但是由于二元函数对象接受两个参数,在绑定成为一元函数对象时需要将原来两个参数中的一个绑定下来。也即通过绑定二元函数对象的一个参数使之成为一元函数对象的。bind1st是绑定第一个参数,bind2nd则是绑定第二个参数。

    #define _CRT_SECURE_NO_WARNINGS
    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <functional>
    using namespace std;
    
    struct MyPrint:public binary_function<int,int,void>
    {
        void operator()(int v, int val) const
        {
            cout << v + val << " ";
            cout << "v:" << v << " val:" << val << endl;
            
        }
    };
    //仿函数适配器 bind1st bind2nd  绑定适配器
    void test01()
    {
        vector<int> v;
        for (int i = 0;i < 10;i++)
        {
            v.push_back(i);
        }
    
        int addNum = 200;
        //绑定适配器 将一个二元函数对象转变成一元函数对象
        for_each(v.begin(), v.end(), bind1st(MyPrint(), addNum));
        /*
        200 v:200 val:0
        201 v:200 val:1
        202 v:200 val:2
        203 v:200 val:3
        204 v:200 val:4
        205 v:200 val:5
        206 v:200 val:6
        207 v:200 val:7
        208 v:200 val:8
        209 v:200 val:9
        */
        for_each(v.begin(), v.end(), bind2nd(MyPrint(), addNum));
        /*
        200 v:0 val:200
        201 v:1 val:200
        202 v:2 val:200
        203 v:3 val:200
        204 v:4 val:200
        205 v:5 val:200
        206 v:6 val:200
        207 v:7 val:200
        208 v:8 val:200
        209 v:9 val:200
        */
    
        //由此可得bind1st与bind2nd的区别:
        //bind1st 将addNum绑定为函数对象的第一个参数;
        //bind2nd 将addNum绑定为函数对象的第二个参数
    }
    
    int main(void)
    {
        test01();
        return 0;
    }

    2、取反适配器:not1和not2

    not1是构造一个与谓词结果相反的一元函数对象,not2是构造一个与谓词结果相反的二元函数对象。
    #define _CRT_SECURE_NO_WARNINGS
    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <functional>
    using namespace std;
    
    struct MyCompare :public binary_function<int, int, bool>
    {
        //由大到小比较
        bool operator()(int v1,int v2) const
        {
            return v1 > v2;
        }
    };
    
    struct MyPrint02
    {
        void operator()(int v)
        {
            cout << v << " ";
    
        }
    };
    
    struct MyGreater5:public unary_function<int,bool>
    {
        //第一个大于5的数
        bool operator()(int v) const
        {
            return v > 5;
        }
    };
    
    //仿函数适配器 not1 not2 取反适配器
    void test02()
    {
        vector<int> v;
        for (int i = 9;i > -1;i--)
        {
            v.push_back(i);
        }
    
        for_each(v.begin(), v.end(), MyPrint02());
        cout << endl;//9 8 7 6 5 4 3 2 1 0
        sort(v.begin(), v.end(), not2(MyCompare()));//由小到大排序
        for_each(v.begin(), v.end(), MyPrint02());//0 1 2 3 4 5 6 7 8 9
        cout << endl;
    
        //not1 not2 区别
        //如果对一元谓词取反,用not1;
        //如果对二元谓词取反,用not2;
    
        vector<int>::iterator it = find_if(v.begin(), v.end(), not1(MyGreater5()));//第一个小于等于5的值
        if (it == v.end())
        {
            cout << "没有找到!" << endl;
        }
        else
        {
            cout << *it << endl;//0
        }
    }
    
    int main(void)
    {
        test02();
        return 0;
    }

    3、函数对象适配器:ptr_fun

     ptr_fun是将一个普通的函数适配成一个仿函数(functor)

    #define _CRT_SECURE_NO_WARNINGS
    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <functional>
    using namespace std;
    
    //仿函数适配器 ptr_fun
    void MyPrint03(int val1,int val2)//普通函数MyPrint03
    {
        cout << val1 + val2 << " ";
        cout << "val1:" << val1 << " val2:" << val2 << endl;
    }
    void test03()
    {
        vector<int> v;
        for (int i = 0;i < 10;i++)
        {
            v.push_back(i);
        }
    
        //ptr_fun:把普通函数 转成 函数对象
        for_each(v.begin(), v.end(), bind1st(ptr_fun(MyPrint03),10));
    /*
    10 val1:10 val2:0
    11 val1:10 val2:1
    12 val1:10 val2:2
    13 val1:10 val2:3
    14 val1:10 val2:4
    15 val1:10 val2:5
    16 val1:10 val2:6
    17 val1:10 val2:7
    18 val1:10 val2:8
    19 val1:10 val2:9
    */
    }
    
    int main(void)
    {
        test03();
        return 0;
    }

    4、成员函数适配器:mem_fun、mem_fun_ref

    mem_fun_ref的作用和用法跟mem_fun一样,唯一的不同就是:当容器中存放的是对象实体的时候用mem_fun_ref,当容器中存放的是对象的指针的时候用mem_fun

    #define _CRT_SECURE_NO_WARNINGS
    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <functional>
    using namespace std;
    
    void test04()
    {
        //如果容器中存放的对象或者对象指针,for_each算法打印的时候,调用类自己提供的打印函数
        vector<Person> v;
        Person p1(10, 20), p2(30, 40), p3(50, 60);
        v.push_back(p1);
        v.push_back(p2);
        v.push_back(p3);
    
        //mem_fun_ref 格式:&类名::函数名
        for_each(v.begin(), v.end(), mem_fun_ref(&Person::show));
        /*
        age:10 id:20
        age:30 id:40
        age:50 id:60
        */
        cout << "-------------" << endl;
        vector<Person*> v1;
        v1.push_back(&p1);
        v1.push_back(&p2);
        v1.push_back(&p3);
    
        for_each(v1.begin(), v1.end(), mem_fun(&Person::show));
        /*
        age:10 id:20
        age:30 id:40
        age:50 id:60
        */
    
        //mem_fun_ref mem_fun 区别?
        //如果存放的是对象指针 使用mem_fun
        //如果存放的是对象 使用mem_fun_ref
    }
    int main(void)
    {
        test04();
        return 0;
    }
  • 相关阅读:
    C# 使用DateTime.TryParseExact将自定义日期类型转换成日期
    ASP.NET WebServices 因 URL 意外地以“/HelloWorld”结束,请求格式无法识别。
    [UE4]计算2点坐标附近的坐标:线性插值法
    [UE4]Selector和Sequence的区别
    [UE4]蒙太奇动画运行时不播放,预览是好的
    [UE4]蓝图函数库小结
    [UE4]C++调用蓝图函数:BlueprintImplementableEvent函数说明符用法
    [UE4GamePlay架构(九)GameInstance(转)
    [UE4]C++取得蓝图控件实例
    [UE4]虚幻4的智能指针
  • 原文地址:https://www.cnblogs.com/yuehouse/p/10116888.html
Copyright © 2020-2023  润新知