如何在类实例的非静态比较方法中使用priority_queue?

时间:2018-12-13 17:17:10

标签: c++ c++11 std priority-queue custom-compare

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

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::vector而不是std::priority_queue。我不想返回.front()的值,而是希望基于自定义比较函数来{{1}的.get()的{​​{1}}值。假设将此自定义比较计算为值和实例.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;

但是这行不通(请参阅Repl.it)。

请问如何解决这个问题?

3 个答案:

答案 0 :(得分:4)

我设法通过使用使其工作:

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 <functional>

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

如果您不希望出现任何性能缺陷,也可以将比较器设置为struct或类似的值,并使用它代替std::function

更新:

带有struct的版本看起来像这样(您可以传递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;
};

答案 1 :(得分:3)

如果您使用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

答案 2 :(得分:1)

如果您要更改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);
    }