這里首先給出容器map的原型:
template <
class Key,
class T,
class Compare = less<Key>,
class Alloc = alloc>
class map{
...
}
可以看到模板參數一共有四個,第一個就是Key,即鍵;第二個就是值;第四個就是空間配置器,默認使用alloc(隨STL版本不同而不同)。那么第三個是啥?
我們知道,map的底層數據結構,其實是樹,更確切的說,是一個RB-tree(紅黑樹)。RB-tree樹在進行插入時,會按照一定的規則把新元素插入特定位置。相應的,進行刪除操作時,也會按一定規則修改樹的結構。此外,樹形結構也是高效率查詢的基本保證。但是,插入、刪除、查詢時都要依賴與節點之間的比較,對於map來說,我們必須提供對Key進行比較的函數或操作符。這也就是第三個模板參數的意義。
默認情況下,第三個模板參數使用less<Key>類型,其中less<T>是一個仿函數。下面給出less的定義:
template<class _Ty>
struct less
: public binary_function<_Ty, _Ty, bool>
{ // functor for operator<
bool operator()(const _Ty& _Left, const _Ty& _Right) const
{ // apply operator< to operands
return (_Left < _Right);
}
};
如果創建一個less類的對象less_obj,然后使用less_obj(A,B)這樣的寫法,就相當於調用了less的operator()方法。而最終執行時,會自動獲取A與B的類型,並使用此類型的operator<來實現less類的operator()方法。到現在為止,就理清了map中的第三個模板參數的所有問題。
接下來的問題就是,如何在map中使用一個結構體作為Key。舉例來說,現在有一個結構體:
typedef struct _info_head{
u_int src_ip;
u_int dest_ip;
u_int src_port;
u_int dest_port;
}info_head;
如果直接使用info_head這個結構體來填入map中的第一個模板參數的位置,並且不指定第三個模板參數的話,那么就會使用less<info_head>作為map中對鍵值進行比較的操作符。而通過上述分析,在less<info_head>中最終使用的,是info_head類型的operator<操作符。那么顯然的,只給出上邊的簡單的對結構體的定義,是不夠的。因此,要想使用結構體來作為map中的Key,那就必須為此結構體重載並實現operator<操作符。如果沒能做到這一點,就會在編譯時報錯,因為編譯器找不到對應的operator<。其中,VS2010下的編譯錯誤代碼是:error C2784。
修改后的結構體代碼如下:
typedef struct _info_head{
u_int src_ip;
u_int dest_ip;
u_int src_port;
u_int dest_port;
bool operator<(const struct _info_head & other) const {
//Must be overloaded as public if this struct is being used as the KEY in map.
if (this->src_ip < other.src_ip) return true;
if (this->dest_ip < other.dest_ip) return true;
if (this->src_port < other.src_port) return true;
if (this->dest_port < other.dest_port) return true;
return false;
}
}info_head;
不過這並不是唯一的辦法。另外一種方式,就是自己寫一個仿函數,實現對info_head類型的比較。然后在info_head作為map中第一個模板參數的時候,填入這個仿函數作為map的第三個模板參數。不過這樣做顯然不如上邊這種辦法簡單,這里也不具體敘述了。
