使用STL的時候難免遇到需要自己定義排序函數的時候,這時候greater
和less
就能起到很大作用。但之前排序的對象都是基本類型(或者基本類型的容器),這次要給自定義類型排序,就遇到了問題。
比如,我有這麼一個場景,我想要給二維空間裏的點做一個優先隊列,從大到小排個序;所以我先定義一個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 thanrhs
.
然後我意識到,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都是常量,如果我重載的運算符的參數爲非常量,相當於把常量賦值給非常量,顯然是不行的。