C++ 无法将派生的比较传递到std::priority\u队列

C++ 无法将派生的比较传递到std::priority\u队列,c++,c++11,std,priority-queue,C++,C++11,Std,Priority Queue,我需要将派生的比较器传递给std::priority\u queue,但由于某种原因,正在调用基类的运算符() 下面是显示此行为的最基本代码: class Base { public: virtual bool operator() (int l, int r) const { cout << "Should not be called" << std::endl; return 0; } virtual ~

我需要将派生的比较器传递给
std::priority\u queue
,但由于某种原因,正在调用基类的运算符()

下面是显示此行为的最基本代码:

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;
}
类基{
公众:
虚拟布尔运算符()(int l,int r)常量{

cout构造函数接受一个
常量比较&
,当将对象传递给函数时,它不会导致任何切片,但是我们在

Copy使用cont的内容构造底层容器c。Copy使用compare的内容构造比较函子comp

由于正在进行复制且模板类型为
Base
,因此您只需复制并存储
a
对象的
Base
部分


您必须将比较对象包装在某种包装器中,并公开一个非虚拟的
操作符()
,该操作符将调用虚拟的
操作符()
传递给
优先级队列的类型
构造函数。

标准规定
比较comp
为23.6.4.1中类模板的值成员。构造函数被称为:

用x初始化comp,用y初始化c(复制或移动 (视情况而定)

因此,即使参数类型实际上是一个
const Compare&
,也有切片

为了解决这个问题,您可以为比较器实现一个pimpl包装器。这个包装器将在内部为实际比较器保留一个
基&
,在它的非虚拟
操作符()
中,只需调用
/
比较器的
虚拟操作符()


请仔细考虑
A
对象的生存期。根据比较器所需的状态,您可以在
Base
中实现一个,并将
Base
作为
std::unique\u ptr
保存在
pimplpcompare
中,您可以将其克隆到它的副本中。或者将其作为
std::shared\u ptr
.

@πνταῥεῖ 为什么要切片?构造函数正在接受
const Compare&
。我不愿意相信它以后会在std库类中以值保存。很抱歉,en.cppreference.com暂停了一会儿。@amit它必须在内部以值保存。如果容器只是保存引用,那么问题中的代码将是未定义的行为因为当构造函数调用返回时,传递给容器的比较器实例的生存期就结束了。当然,它是按值保存的。“您只需要复制和存储对象的基本部分。”这不正是切片吗?问题是“我做错了什么?”。或者更明确地说,我如何将比较器传递给将在其生命周期内使用的优先级_队列?@πάνταῥεῖ 我重新编写了它,以澄清我的意思是在传递给函数时它不是切片。我相信当它声明为(2)“Move用std::Move(compare)构造比较函子comp时是错误的。在所有构造函数中,compare由
const comp&
std::Move(compare)
的类型为
const Comp&&
,但move构造函数将采用
Comp&&
,因此它将调用复制构造函数。libstdc++似乎不会在比较器上进行任何移动。