cpp 比 c 方便不少不光因為其支援物件導向支援class
,同樣還因為其支援泛型程式設計,有方便的stl
庫。泛型要比巨集強大的多,是一種設計更巧妙的編譯期動態機制,型別安全,使得一些通用演算法的封裝變得十分方便。模板操作的是型別,特化的時候編譯器會做型別推導,這是模板乙個核心特徵。
根據c++標準,當乙個模板不被用到時它就不應該被具體化。對於cpp
編譯器是如何特化,編譯成最終**,用到了惰性求值和模式匹配。這篇文章簡單介紹了這兩個原理:學習haskell。
對於實際的使用,記住下面兩點:
這裡主要說一下 c++ 標準庫,尤其是stl
涉及比較操作時的常用比較器。這裡是stl源**。
傳入函式編譯器來做型別推導,進行模板特化。看sort
函式的模板宣告:
// 可以看出,排序要求容器支援隨機訪問迭代器,類似於陣列的那種下標偏移訪問
// 這裡 _compare 是型別, __comp 是例項,呼叫 sort 需要傳入的就是 __comp 例項
template
inline
void sort(_randomaccessiter __first, _randomaccessiter __last,
_compare __comp)
乙個例子如下:
typedef
struct tagnode node;
bool comp(const node &a, const node &b)
int main()
, , , , };
// 編譯器會進行型別推導做模板特化
sort(a, a + 5, comp);
return
0;}
仿函式functor的英文解釋為something that performs a function,即其行為類似函式的東西。c++中的仿函式是通過在類中過載()運算子實現,使你可以像使用函式一樣來建立類的物件。要求傳入仿函式的地方也很好理解,一般c++模板,尖括號<>
裡面放的是型別,自然這需要比較器的時候傳入的也是比較器的型別,這就是用到仿函式的地方。
首先,看一下stl
原始碼的模板宣告:
// map 和 set 底層儲存結構式都是紅黑樹
// forward declarations of operators == and <, needed for friend declarations.
template
class _compare __stl_dependent_default_tmpl(less<_key>),
class _alloc = __stl_default_allocator(_tp) >
class
map;
template
),class _alloc = __stl_default_allocator(_key) >
class
set;
// priority_queue 有優先順序,要求元素可比較。queue 和 priority_queue 預設的底層儲存結構也不同
// queue 預設用的是 deque 雙端佇列,priority_queue 用的是 vector
// priority_queue 實現使用的預設比較是 operator< ,是最大堆資料結構,即佇列頭元素值最大
template
class _sequence __stl_dependent_default_tmpl(deque
<_tp>) >
class
queue;
template
class _sequence __stl_dependent_default_tmpl(vector
<_tp>),
class _compare
__stl_dependent_default_tmpl(less)
class priority_queue; // 注意點:如果自己傳入自己的仿函式比較,那麼第二個儲存型別也要傳入不能預設
對於priority_queue
用法,這篇文章裡的例子很不錯stl裡的priority_queue用法。
乙個注意點就是:如果使用自定義比較,使用仿函式,那麼使用時必然也要傳入第二個模板型別引數,要麼都預設,要麼都傳入。下面給乙個例子:
#include
#include
using
namespace
std;
typedef
struct tagnode
node;
/* 針對某種型別的自定義比較仿函式,cpp 中 struct 相當於全部 public 的 class */
struct classcomp
};int main()
, , , , };
// classcomp 必須是針對 node 型別的比較仿函式,第二個預設儲存結構也不能少
priority_queuevector
, classcomp> prique;
for(unsigned
int i = 0; i < sizeof(a)/sizeof(a[0]); ++i)
while(!prique.empty())
return
0;}
過載<
運算子,這種方式通用性會比較強,這種方式使得複雜結構變得像基本資料型別一樣可比較了。這樣就不用傳比較器了,因為預設的比較器這時已經生效了。對於 cpp **,過載運算子不管對於 struct 還是 class 都是很方便的,都是在自己定義的結構體或類型別裡加乙個過載的函式即可。這種方法缺點也是比較明顯的,如果有兩個模板容器對同一自定義資料結構(結構體或者類)需要不同的比較器,那麼過載<
這種方法就沒有上面的自定義比較器(比較函式或者仿函式)適用了。
同樣給個例子:
#include
#include
using
namespace
std;
// 過載運算子 讓cpp**的表達力有很大提公升,比如map過載可以翻遍用獲取指定key的value
// 還有如果定義了一些矩陣運算什麼的,過載 * 就更加方便靈活了
struct node
};int main()
, , , , };
priority_queueprique; //node 型別過載了 < ,變得像 int 等基本資料型別一樣可比較了
for(unsigned
int i = 0; i < sizeof(a)/sizeof(a[0]); ++i)
while(!prique.empty())
return
0;}
對於 cpp 中需要自定義比較時,如果以後的操作比較都是定的,可以用過載,否則還是用自定義比較函式和仿函式。還有就是stl
中優先順序佇列priority_queue
, 自定義仿函式是模板的第三個型別,如果自定了那麼第二個模板引數也要傳入,一般用vector
就可以。
c++ 自定義比較:仿函式、函式與過載操作符
map自定義比較函式
from template class alloc alloc 第乙個引數key是關鍵字型別 第二個引數t是值型別 第三個引數compare是比較函式 仿函式 第四個引數是記憶體配置物件 map中的關鍵字,起碼必須有 這個比較操作符。我們知道,int,float,enum,size t等等簡單關鍵字...
自定義比較函式mystrcmp
實現乙個兩字串比較的函式 mystrcmp 不允許呼叫標準庫中的字串處理函式。當兩字串相等時,該函式返回 0 當第乙個字串大於第二字串時,該函式返回 1 當第乙個字串小於第二字串時,該函式返回 1。輸入格式 兩行,每行乙個字串,每個字串的長度不超過30。輸出格式 根據兩字串的大小,對應輸出 0,1,...
自定義lower bound比較函式
過載比較符號或者自定義比較函式均可。記得比較的時候需要放結構體進去比較。如用vetor存結構體比較或者直接結構體比較。include include include include include include include include include include include inc...