无法将派生的Compare传递给std :: priority_queue

时间:2016-02-25 18:15:50

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

我需要将派生的比较器传递给std::priority_queue,但由于某种原因,基类'正在调用operator()。

以下是显示此行为的最小代码:

class Base {
    public:
    virtual bool operator() (int l, int r) const {
        cout << "Should not be called" << std::endl;
        return 0;
    }
    virtual ~Base() {}
};
class A : public Base { 
    public:
    bool operator() (int l, int r) const override {
        cout << "Should be called!!!!";
        return l < r;
    }
};
int main() {
    priority_queue<int, vector<int>, Base> pq((A()));
    pq.push(1);
    pq.push(2);
    pq.push(3);
    pq.push(0);
    cout << pq.top();
    return 0;
}

The code is available on ideone as well

请注意,我无法使用priority_queue<int, vector<int>, A>,因为我有Base的其他子类,这将导致大量代码重复 1

我做错了什么?如何将比较器传递给将在其生命周期内使用的priority_queue?

(1)我知道我可以通过使用接受priority_queue<int,vector<int>, T>的模板函数来绕过代码重复问题 - 但我真的不愿意。

2 个答案:

答案 0 :(得分:8)

该标准将Compare comp指定为 23.6.4.1 中类模板的值成员。据说构造者:

  

使用x初始化comp,使用y初始化comp(复制构造或移动   酌情建造);

因此,即使参数类型实际上是const Compare&,您也会进行切片。

要解决这个问题,你可以为比较器实现一个pimpl-wrapper。这个包装器会在内部保持Base&到实际的比较器,而在它的非虚拟operator()中只需调用virtual operator() / Base比较器的A

请仔细考虑A对象的生命周期。根据比较器所需的状态,您可以在Base中实施virtual clone-method。并将Base作为std::unique_ptr<Base>保留在PimplCompare中 - 您将其复制到其副本中。或者您将其保留为std::shared_ptr<Base>

答案 1 :(得分:5)

构造函数采用const Compare&,在将对象传递给函数时不会导致任何切片,但我们在documentation

  

使用cont的内容复制构造底层容器c。复制 - 构造比较函子comp与compare的内容。

由于副本正在发生且模板类型为Base,因此您只需要复制并存储Base对象的A部分。

您必须将比较对象包装在某种包装器中,并公开一个非虚拟operator (),它将调用传递给operator()构造函数的类型的虚拟priority_queue。 / p>