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

一、谓词概念

谓词是指普通函数或重载的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;
}

 

posted @ 2018-12-13 22:27  悦悦的小屋  阅读(384)  评论(0编辑  收藏  举报