• C++仿函数


    仿函数

    仿函数又称为函数对象,是一种能够行使函数功能的类,该类重载了operator()运算符,调用仿函数的时候实际上就是通过类对象调用重载后的operator操作符,重载operator()和重载普通的函数效果相同,当参数类型不同时会执行不同的代码逻辑。仿函数使用
    比如自定义了一个仿函数A

    #include 
    #include 
    using namespace std;
    class A{
    public:
    int operator() (int a, int b){
    return a+b;
    }
    double operator() (double a, double b){
    return (a+b)*2;
    }
    };
    int main(){
    A a;
    auto c1 = a(1, 2);
    cout << typeid(c1).name() << " " << c1 << endl;
    auto c2 = a(11.3, 2.4);
    cout << typeid(c2).name() << " " << c2 << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    C++标准库中的仿函数存在在于functional.h中,平时用到的最多的是greater,less这两个,这两个函数常被用做排序函数的参数。在排序函数中greater和less这两个函数可以被等效的lambda表达式替换。但是在优先队列中,不能直接使用lambda表达式替换。

    所以才会接触到仿函数这个概念。优先队列自定义比较规则,可以使用仿函数或者对被比较的类重载小于操作符。由于C++规定操作符重载必须至少有一个类类型的操作数,因此当优先队列中的元素不是自定义类的时候,则没法对其重载小于操作符,此时只能实用仿函数来实现自定义的比较规则。
    以下是为优先队列定义仿函数的示例

    #include 
    #include 
    #include 
    using namespace std;
    class comp{
    public:
    bool operator(const pair &a, const pair &b) {
    return a.second < b.second;
    }
    };
    int main(){
    priority_queue, vector>, comp> q;
    q.push({1,3});
    q.push({2,4});
    q.push({3,6});
    auto p = q.top();
    cout << p.first << " " << p.second << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    函数对象 vs 模板类型参数
    很多人C++初学者会有这样的疑惑,在sort中可以使用lambda,而在优先队列的定义中不能使用,相反,在优先队列中可以使用仿函数,而在sort中则不能使用仿函数。
    这个问题的根源在于没有分清楚仿函数(函数对象)和模板类型参数之间的关系。
    sort函数的原型为

    template 
    void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp);
    
    • 1
    • 2

    可以看到 comp是一个函数对象,因为lambda对象也属于函数对象,所以可以作为排序的参数。C++中凡是能够调用()运算符的就都是函数对象,包括函数、函数指针、重载了()运算符的对象,以及lambda对象。
    优先队列的构造函数原型为

    template<
    class T,
    class Container = std::vector,
    class Compare = std::less
    > class priority_queue;
    
    • 1
    • 2
    • 3
    • 4
    • 5

    填入尖括号中的应该是类型的名字,即typename,当然不能使用lambda作为typename,但是我们使用decltype来获得lambda的类型,作为typename,然后在构造函数的参数中把lambda示例传进去,就能work。
    示例如下

    #include
    #include
    using namespace std;
    int main(){
    auto comp = [](const pair &a, const pair &b){
    return a.second < b.second;
    };
    priority_queue, vector>, decltype(comp)> q(comp);
    q.push({1,3}); q.push({2,4}); q.push({3,6});
    auto p = q.top();
    cout << p.first << " " << p.second << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
  • 相关阅读:
    浅谈如何更好的进行需求评审
    STM32通用定时器产生PWM信号
    Hadoop集群安装和搭建
    实现安全的服务通信:探索如何使用服务网格来确保服务间的安全通信
    STM32CubeMX教程25 PWR 电源管理 - 睡眠、停止和待机模式
    2022年全国最新消防设施操作员(中级消防设施操作员)真题题库及答案
    硬件管理平台 - 公共项目搭建(Nancy部分)
    讯飞有一个可以根据描述文本自动生成PPT的AI接口,有趣
    Internet Download Manager2022中文版免费下载
    面向对象编程原则(07)——接口隔离原则
  • 原文地址:https://blog.csdn.net/neuzhangno/article/details/128071568