lambda 与 priority_queue 以及 function 以及 bind

Posted 远近闻名的学渣

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了lambda 与 priority_queue 以及 function 以及 bind相关的知识,希望对你有一定的参考价值。

lambda是一种可调用对象,它是一个对象,每个lambda都有自己不同的类型。

年轻时以为STL和lambda混用时会有一些奇怪现象,比如我无法像这样定义优先队列:

priority_queue<int, vector<int>, [](int a, int b) {return a > b;}> que;

但是却可以这样用sort

sort (vec.begin(), vec.end(), [](int a, int b) {return a < b;});

 以及可以这样用sort

bool less(int a, int b) { return a < b;}

typedef bool (*cmp) (int, int);
cmp mycmp = less;
sort (vec.begin(), vec.end(), mycmp);

sort (vec.begin(), vec.end(), less);  

 

之所以会出现这样的疑问,是因为没有搞清楚函数对象 (也叫可调用对象) 和 模板的类型参数之间的关系, 首先说明如何正确的使用 lambda 对象来实例化priority_queue :

#include <iostream>
#include <queue>
#include <vector>
#include <utility>
 
using my_pair_t = std::pair<size_t,bool>;
 
using my_container_t = std::vector<my_pair_t>;
 
int main()
{
    auto my_comp =
        [](const my_pair_t& e1, const my_pair_t& e2) 
        { return e1.first > e2.first; };
    std::priority_queue<my_pair_t,
                        my_container_t,
                        decltype(my_comp)> queue(my_comp);
    queue.push(std::make_pair(5, true));
    queue.push(std::make_pair(3, false));
    queue.push(std::make_pair(7, true));
    std::cout << std::boolalpha;
    while(!queue.empty()) 
    {
        const auto& p = queue.top();
        std::cout << p.first << " " << p.second << "\n";
        queue.pop();
    }
}

1, 首先这里的my_comp是一个对象,由于每个lambda对象都有一个匿名的类型,所以只能用auto来表达my_comp的类型

2, 优先队列的声明是这样的:

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

所以要实例化一个优先队列,尖括号里得填typename啊, 由于 lambda 对象的类型是匿名的,所以用decltype搞定,再然后光这样是不行的,这会来看构造函数:

explicit priority_queue( const Compare& compare = Compare(),
                         const Container& cont = Container() );

可以看到,如果我们构造时,不指定特定的compare对象,那么就用typename Compare的默认构造函数构造一个,然而lambda表达式的匿名类型是没有默认构造函数的,

所以想要正确初始化这个优先队列,还得在构造函数里再把lambda表达式本身传进去

 

3, 函数指针,函数, lambda表达式,函数对象之间的关系

首先看sort的一个重载声明:

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

这里sort接受一个函数对象,所以直接给传递lambda对象是可以的,因为lambda对象属于函数对象嘛,在C++里凡是能够使用函数调用运算符的,都是函数对象,所以

函数对象有: 函数, 函数指针, 重载了()的类的对象,以及lambda对象。

注意,函数和函数指针是两个不同的东西,就像虽然数组在作为参数时会被当成指针传递,但是他们依旧不是同一个东西,即:

虽然在非引用时,数组和函数都会被转换成指针(包括模板参数推断也会这样),但是他们仍旧不是指针,指针的例子不用多说,举个函数的例子:

template <typename T>
void t(const T& t) {
    cout << std::is_pointer<T>::value << endl;
    t();
}

template <typename T>
void e(T t) {
    cout << std::is_pointer<T>::value << endl;
    t();
}

void f() {
}
 int main() {
    t(f);

    cout << endl;
    e(f);
    return 0;
}

 

第一次调用输出的是0,第二次则是1,这也就是说函数本身 和 函数指针也是两个东西

 

至此也就解释了一开始说到的如何使用sort以及priority_queue的原因了

以上是关于lambda 与 priority_queue 以及 function 以及 bind的主要内容,如果未能解决你的问题,请参考以下文章

C++ std::priority_queue 使用 lambda 表达式

c++优先级队列priority_queue使用lambda表达式出错问题

c++优先级队列priority_queue使用lambda表达式出错问题

STL详解—— priority_queue的使用与模拟实现

具有 lambda 函数错误的优先级队列

通过引用传递自定义优先级队列