2013-11-24 84 views
16

標準庫將std :: hash作爲專門用於不同類型的模板結構體來實現。它是這樣使用的:爲什麼std ::散列結構而不是函數?

#include <iostream> 
#include <functional> 

int main() 
{ 
    std::hash<int> hasher; 
    std::cout << hasher(1337) << std::endl; 

    return 0; 
} 

我的問題是什麼是這種設計選擇背後的推理。爲什麼它不是爲模板功能實現和使用這樣的:

#include <iostream> 
#include <functional> 

int main() 
{ 
    std::cout << std::hash<int>(1337) << std::endl; 

    return 0; 
} 
+0

這兩個例子是相同的,唯一的區別在於第二個對象是未命名的。 – user2485710

+0

無序的關聯容器有一個模板類型參數來指定散列;這允許使用有狀態的哈希對象(例如,使用在哈希上異或的特殊值)。獲取函數模板專業化的類型沒有一個很好的語法。 – dyp

+1

@ user2485710第一個例子編譯,第二個例子不編譯。第二個需要寫成'std :: hash ()(1337)'來使用一個未命名的臨時結構體。 – hvd

回答

16

有多個原因,足夠每一個很好的,只是選擇:

  1. 您可以部分專門化類模板,但您只能使用完全專用的函數模板(至少目前爲止)。因此,您可以使用std::hash<T>作爲類模板,提供整套相關模板參數的替代。請注意,部分重載並不能解決問題,因爲散列函數需要以某種方式指定爲不能用重載函數完成的對象(除非通過對象訪問這些對象,但這是與之相區別的)。
  2. 無序關聯容器使用靜態實體(如果特定類型支持,也可動態定製)進行參數化,這更容易使用類模板完成。
  3. 由於用於散列函數的實體是可定製的,所以選擇在使用類型或函數指針進行自定義之間進行選擇。函數指針通常很難內聯,而類型的內聯成員函數對於內聯而言不重要,這提高了簡單函數的性能,例如相當簡單的計算一個簡單的哈希值。
+3

公平地說,默認的哈希函數可以調用一個函數,然後可以爲非支持的類型嘗試調用'.hash()'方法,這將允許上述所有內容,允許adl散列(這比強制'std'注入),並允許對象自己散列,如果他們想。但是這違反了KISS,即使它符合「少」和「開始」的工作方式。 – Yakk

4

模板功能不能部分專用的類型,而專門針對不同類型的類模板std::hash

而且,在這個模板類基礎的方式,你可以做一些元編程如訪問返回類型和密鑰類型如下圖所示:

std::hash<X>::argument_type 
std::hash<X>::result_type 
相關問題