使用STL的时候难免遇到需要自己定义排序函数的时候,这时候greaterless就能起到很大作用。但之前排序的对象都是基本类型(或者基本类型的容器),这次要给自定义类型排序,就遇到了问题。

比如,我有这么一个场景,我想要给二维空间里的点做一个优先队列,从大到小排个序;所以我先定义一个Point类。因为需要进行大于的比较,所以我重载一个>运算符:

class Point
{
    int val, x, y;
    Point(int val, int x, int y) : val(val), x(x), y(y) {}
    bool operator>(const Point &p) const { return val > p.val; }
};

然后再定义一个优先队列(用STL的优先队列):

priority_queue<Point, vector<Point>, greater<Point>> q;

到这里都没什么问题。然后我插入一个坐标为(1, 1),值为1的点:

q.emplace(1, 1, 1);

然后就报错了。

找了半天也不知道为啥,后来查了一下greater的文档,看到里面是这么写的:

std::greater::operator()

bool operator()( const T& lhs, const T& rhs ) const;(until C++14)
constexpr bool operator()( const T& lhs, const T& rhs ) const;(since C++14)

Checks whether lhs is greater than rhs.

然后我意识到,greater的内部实现是一个const的成员函数,也就是常成员函数。而我们知道,常成员函数是不能调用普通的成员函数的。原因很简单,因为常成员函数是保证不会修改成员变量的,而普通成员函数不保证是否会修改成员变量,如果常成员函数调用了普通成员函数,就有可能会出现声明和实际行为不一致的情况(声明保证不会修改,却偷偷把值给改了),这种情况是不允许出现的,所以就报错了。

解决办法也很简单,加个const,声明为常成员函数就行了:

class Point
{
    int val, x, y;
    Point(int val, int x, int y) : val(val), x(x), y(y) {}
    bool operator>(const Point &p) const { return val > p.val; }
};

另外,参数里的const也是不能少的。为啥呢,理由还是和刚才一样,greater在调用的时候传入的lhs和rhs都是常量,如果我重载的运算符的参数为非常量,相当于把常量赋值给非常量,显然是不行的。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐