带有 lambda 比较器错误的 C++ priority_queue

Posted

技术标签:

【中文标题】带有 lambda 比较器错误的 C++ priority_queue【英文标题】:C++ priority_queue with lambda comparator error 【发布时间】:2011-08-14 01:04:16 【问题描述】:

我尝试在 VC2010 中编译以下错误代码,但我收到错误 C2974 这仅在我包含 lambda 表达式时发生,所以我猜它与此有关.

typedef pair<pair<int, int>, int> adjlist_edge;
priority_queue< adjlist_edge , vector<adjlist_edge>,
    [](adjlist_edge a, adjlist_edge b) -> bool 
        if(a.second > b.second) return true;  else  return false; 
    > adjlist_pq;

我知道模板定义的形式是正确的

priority_queue<int , vector<int>, greater<int>> pq;

按预期工作。任何想法我做错了什么?我可能忽略的看起来错误的 lambda 是否有明显错误?感谢阅读!

【问题讨论】:

***.com/questions/3867276/…的可能重复 【参考方案1】:

首先定义 lambda 对象,然后使用 decltype 将其传递给模板的类型,并直接将其传递给构造函数。

auto comp = []( adjist a, adjlist b )  return a.second > b.second; ;
priority_queue< adjlist_edge , vector<adjlist_edge>, decltype( comp ) >
     adjlist_pq( comp );

【讨论】:

谢谢,如果我必须单独声明它就可以了,你认为使用 lambda 对象而不是仿函数有什么好处吗? Re:默认构造函数:[expr.prim.lambda]/19 表示默认构造函数和复制赋值运算符被删除,复制构造函数和析构函数被隐式定义,用于闭包。 为什么还要直接传给构造函数? @Ari 因为 lambda 函数的类从来没有默认构造函数,即使它没有捕获。所以priority_queue只能通过复制来构造比较函数对象。 他们是这个的现代化版本还是仍然是最新的?【参考方案2】:

priority_queue 将比较器作为模板参数。 Lambda 函数是对象,因此不能用作模板参数(只有极少数类型可以是整数类型)。

你可以在那里尝试使用decltype

priority_queue< adjlist_edge , vector<adjlist_edge>,
               decltype( [](adjlist_edge a, adjlist_edge b) -> bool 
                if(a.second > b.second) return true;  else  return false; 
               )>
adjlist_pq( [](adjlist_edge a, adjlist_edge b) -> bool 
                if(a.second > b.second) return true;  else  return false; 
              );

如果失败(它会),您可以使用function&lt;&gt;

priority_queue< adjlist_edge , vector<adjlist_edge>,
                function<bool(adjlist_edge,adjlist_edge)> >
adjlist_pq( [](adjlist_edge a, adjlist_edge b) -> bool 
                if(a.second > b.second) return true;  else  return false; 
             );

【讨论】:

+1 表示比 interjay 更接近,但这仍然行不通,因为每个 lambda 函数都有唯一的类型,即使是两个具有相同定义的对象。 函数更好,因为它不重复代码(显然,这是唯一正确的做法)。 @Alexandre:还有另一种选择,它牺牲了单线但比function更干净。 您需要在priority_queue 中添加结束&gt;。由于 6 个字符,无法编辑。要求。【参考方案3】:

接受的答案回答了如何将带有 lambda 表达式的 priority_queue 定义为自定义 Compare 对象。 我将解决问题的另一个方面:为什么以您的方式定义 pq 时会失败:

typedef pair<pair<int, int>, int> adjlist_edge;
priority_queue< adjlist_edge , vector<adjlist_edge>,
    [](adjlist_edge a, adjlist_edge b) -> bool 
        if(a.second > b.second) return true;  else  return false; > adjlist_pq;

为什么我们必须在构造优先级队列时将 lambda 作为参数传递?原因在于 lambda 表达式没有默认构造函数。所以如果你在构造优先级队列的时候没有提供它,就会调用lambda表达式的“假定存在的默认构造函数”。显然,它会失败。

关于您的问题:比较对象(lambda 或函数对象)是否具有默认构造函数会有所不同。

【讨论】:

【参考方案4】:

以下是使用优先级队列构建 minheap 的示例。我使用了 lambda 来定义比较器,给定由 vector&lt;ListNode *&gt; &amp;lists 定义的链表

// This comparator will be used to build minheap.
auto comp = [&](ListNode *a, ListNode *b) 
    return a->val > b->val;
;

// This priority queue is the min heap
priority_queue<ListNode *, vector<ListNode *>, decltype(comp)> pq(comp);

【讨论】:

以上是关于带有 lambda 比较器错误的 C++ priority_queue的主要内容,如果未能解决你的问题,请参考以下文章

带有非 const 字符串的 C++ lambda 到 std::function 错误

分段错误:C++ 使用 lambda 比较器对字符串向量进行排序

Qt C++ 将带有非空签名的信号连接到 lambda

C++里使用二分法查找和lambda表达式进行比较

VS Code 中的 Lambda 表达式 C++ 错误

lambda 的 C++ 三元赋值