如何将 priority_queue 与类实例的非静态比较方法一起使用?

Posted

技术标签:

【中文标题】如何将 priority_queue 与类实例的非静态比较方法一起使用?【英文标题】:How to use priority_queue with a non-static compare method of class instance? 【发布时间】:2018-12-13 17:17:09 【问题描述】:

假设我有一个像这样的简单类:

class Test 
public:
  Test(int reference)  m_reference = reference; 
  void feed(int x)  m_data.push_back(x); 
  int get()  return m_data.front(); 
private:
  int m_reference;
  std::vector<int> m_data;
;

我想将值输入std::priority_queue,而不是std::vector。我不想返回 .front() 值,而是想基于自定义比较函数 .get() .top()priority_queue 值。假设这个自定义比较被计算为一个值和实例reference之间的绝对差。

不知道如何在我的类属性中声明std::priority_queue

我试过了:

bool compare(int a, int b) 
    return std::abs(a - m_reference) < std::abs(b - m_reference);

然后:

std::priority_queue<int, std::vector<int>, decltype(&Test::compare)> m_priority;

我也尝试过像这样使用std::function,但这会引发多个错误:

std::function<bool(int a, int b)>> pq([this](int a, int b)
   return std::abs(a - m_reference) < std::abs(b - m_reference);
);

但这不起作用(请参阅Repl.it)。

你知道如何解决这个问题吗?

【问题讨论】:

@MatthieuBrucher 如果我添加static,尽管reference 属性是非静态的,这仍然有效吗? 如何使用 lambda 并捕获要用于比较的实例? @πάνταῥεῖ 我试过但无法捕获[this](因为我需要它用于m_reference 属性)。但是我对 lambda 函数没有太多经验,也许有一个解决方法。 @Delgan 你能在你的问题中展示你对 lambda 的尝试吗?也许我们可以解决你的问题。一般应该可以捕获this. @πάνταῥεῖ priority_queue 声明使用 lambda 存在问题 【参考方案1】:

我设法通过使用:

std::function<bool(int,int)> comp = [this](int a, int b)  return std::abs(a - m_reference) < std::abs(b - m_reference); ;

Test(int reference) : m_priority(comp)  m_reference = reference; 

std::priority_queue<int, std::vector<int>, decltype(comp)> m_priority;

您还需要#include &lt;functional&gt;

如果我正确理解您的问题,这就是您想要的吗?

如果您不希望出现任何性能缺陷,您也可以将比较器设为 struct 或其他东西,并使用它来代替 std::function

更新:

带有结构的版本看起来像这样(你可以传递一个this 指针而不是引用int 或者你喜欢它):

#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <cmath>

class Test 
public:
    Test(int reference) : m_priority(comp(m_reference))  m_reference = reference; 
    void feed(int x)  m_data.push_back(x); 
    int get()  return m_priority.top(); 

    struct comp 
        int& reference;
        comp(int& ref) : reference(ref) 
        bool operator()(int a, int b)  return std::abs(a - reference) < std::abs(b - reference); ;
    ;

private:
    int m_reference;
    std::vector<int> m_data;
    std::priority_queue<int, std::vector<int>, comp> m_priority;
;

【讨论】:

好吧,看来使用struct 的解决方案可能是最好的解决方案。感谢您的回答!【参考方案2】:

如果您可以使用 std::function(它可能会有轻微的开销),它会起作用,但您尝试将 lambda 提交到类型声明中:

std::priority_queue<
        int,
        std::vector<int>,
        std::function<bool(int,int)> comp = [this](int a, int b)  return std::abs(a - m_reference) < std::abs(b - m_reference); > m_priority;

这行不通。您需要使用std::function 作为类型:

std::priority_queue<
        int,
        std::vector<int>,
        std::function<bool(int,int)>> m_priority;

然后将 lambda 作为参数提交到m_priority ctor:

Test(int reference) :
    m_reference( reference ),
    m_priority( [ref=reference]( int a, int b ) 
        return std::abs( a - ref ) < std::abs( b - ref ); 
     )
 
 

然后它会工作。 Live example

【讨论】:

【参考方案3】:

如果您要更改 m_reference 的值,则需要重新排序 std::priority_queue。下面是一种(可能)笨拙的方法,如果经常这样做和/或队列很大,这将非常昂贵,但它可以完成工作。该代码旨在作为@Slavas 答案的附加组件。

public:
    void set_reference(int x) 
        m_reference = x;
        sort();
    
private:
    void sort() 
        std::priority_queue<int, std::vector<int>, std::function<bool(int,int)>> tmp(
            [this](int a, int b)  return std::abs(a - m_reference) < std::abs(b - m_reference); 
        );
        while(m_priority.size()) 
            tmp.emplace(std::move(m_priority.top()));
            m_priority.pop();
        
        std::swap(tmp, m_priority);
    

【讨论】:

以上是关于如何将 priority_queue 与类实例的非静态比较方法一起使用?的主要内容,如果未能解决你的问题,请参考以下文章

打字稿装饰器与类继承

[Python]-8-对象与类(中)

prority_queue 的用法 实例

STL —— priority_queue的用法及实例

Java类的定义与类的实例化

STL priority_queue 的自定义分配器