美文网首页
C++仿函数

C++仿函数

作者: 克罗地亚催眠曲 | 来源:发表于2020-07-12 20:21 被阅读0次
    仿函数

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

    仿函数使用

    比如自定义了一个仿函数A

    #include <typeinfo>
    #include <iostream>
    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;
    }
    

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

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

    #include <iostream>
    #include <queue>
    #include <vector>
    using namespace std;
    class comp{
    public:
      bool operator(const pair<int, int> &a, const pair<int,int> &b) {
        return a.second < b.second;
      }
    };
    int main(){
      priority_queue<pair<int,int>, vector<pair<int,int>>, comp> q;
      q.push({1,3});
      q.push({2,4});
      q.push({3,6});
      auto p = q.top();
      cout << p.first << " " << p.second << endl;
    }
    
    函数对象 vs 模板类型参数

    很多人C++初学者会有这样的疑惑,在sort中可以使用lambda,而在优先队列的定义中不能使用,相反,在优先队列中可以使用仿函数,而在sort中则不能使用仿函数。

    这个问题的根源在于没有分清楚仿函数(函数对象)和模板类型参数之间的关系。
    sort函数的原型为

    template <class RandomAccessIterator, class Compare>
      void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp);
    

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

    template<
        class T,
        class Container = std::vector<T>,
        class Compare = std::less<typename Container::value_type>
    > class priority_queue;
    

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

    #include<queue>
    #include<iostream>
    using namespace std;
    int main(){
      auto comp = [](const pair<int,int> &a, const pair<int,int> &b){
        return a.second < b.second;
      };
      priority_queue<pair<int,int>, vector<pair<int,int>>, 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. https://www.cnblogs.com/64open/p/5267678.html

    相关文章

      网友评论

          本文标题:C++仿函数

          本文链接:https://www.haomeiwen.com/subject/vyrncktx.html