2012-01-13 76 views
2

如果我有下面的模板參數:減少模板策略雜波

template <typename T_Key, typename T_Value, typename T_HashFunc, 
    typename T_ExtractKey, typename T_EqualKey, typename T_RehashClass, typename T_HashcodeClass> 
    class Hashtable { /* ... */ }; 

T_RehashClassT_HashcodeClass是採取T_Key, T_Value, T_HashFunc, T_ExtractKey and T_EqualKey以及兩個模板類。我希望這些類可以從Hashtable的typedef列表中獲取類型(Hashtable中的所有模板參數類型均爲類型定義)。

請注意,T_RehashClassT_HashcodeClass也可以由用戶創建(默認提供),如果用戶希望可以有其他模板參數。

現在,任何類T_RehashClass必須有T_Key, T_Value等模板參數填寫,我認爲這是代碼重複。我希望該課程知道Hashtable,以便它可以通過創建自己的typedef自動訪問其typedefs並自動推斷T_Key, T_Value等。不幸的是,在這種情況下,我得到了循環依賴。

這類問題一般如何解決?

另請注意,我遵循的是EASTL,EASTL使用多重繼承來繼承T_RehashClassT_HashnodeClass,因此Hashtable擁有更多的模板參數。我想知道是否有解決方法(即不從策略繼承並將它們作爲從策略繼承的模板參數降低靈活性)。我認爲的


一個解決辦法是讓具有所有模板參數從T_KeyT_EqualKey模板結構。然後,Hashtable聲明將是:

template <typename T_HashtableParams, typename T_RehashClass = default_rehash_class<T_HashtableParams>, typename T_HashcodeClass = default_hashnode_class<T_HashtableParams> > 
    class Hashtable { /* ... */ }; 

T_RehashClassT_HashcodeClass可以再取這將消除代碼重複的默認值。這種方法的問題是用戶使用起來更麻煩。

+0

我很好奇你爲什麼需要這麼多的靈活性,允許用戶指定表會變得如何改頭換面......這真的好像YAGNI應該在踢 - 你想解決什麼問題需要這麼多的定製? – Yuushi 2012-01-13 03:47:02

+0

'T_ExtractKey'和'T_EqualKey'是多餘的(你可以提取關鍵的平等的測試,沒有必要爲一個獨立的仿函數的一部分),以及'T_HashFunc'和'T_HashcodeClass'似乎也。 – 2012-01-13 03:48:40

+0

@CatPlusPlus:那麼,在這個實現,但它有節點存儲hashkey與否的選項。 'T_HashcodeClass'有兩個不同的實現,一個假設hashkey存儲,另一個不存在。至於其他人,我也不完全確定,但EASTL擁有它。現在我知道這是不是包括它的理由,但我想筆者知道的比我多,我最終會明白(以下簡稱「最終understand'部分做了其他容器發生在我身上,而下面EASTL) – Samaursa 2012-01-13 03:55:21

回答

1

參見例如,現代C++設計(第1.5.1節:使用模板參數實現策略)。這個想法是讓T_RehashClass和T_HashcodeClass成爲模板參數。這些類將T_Key,T_Value和其他任何參數作爲自己的參數。爲了避免重新輸入,您可以繼承這些模板所需的實例。

template < 
    typename T_Key, 
    typename T_Value, 
    typename T_HashFunc,  
    typename T_ExtractKey, 
    typename T_EqualKey, 
    template<typename, typename /*, more params */> class T_RehashClass, 
    template<typename, typename /*, more params */> class T_HashcodeClass 
> class Hashtable 
: 
    public T_RehashClass<T_Key, T_Value /*, more params */>, 
    public T_HashcodeClass<T_Key, T_Value /*, more params */> 
{ /* ... */ }; 

注意:你真正需要的「類」,而不是「類型名稱」中T_RehashClass和T_HashcodeClass的前面,因爲他們是模板的名稱,而不是模板類型!

+0

感謝。這實際上與EASTL正在做的非常接近。我讀現代C++設計將重新您指出我同意的配置有趣的是隻有誰寫它的人的部分(+1) – Samaursa 2012-01-18 02:14:50

2

我不確定爲hash和rehash類指定不同的T_Key和T_Value類型是非常有趣的。如果我正在解決這個問題,我會嘗試爲key/val首先設置一個策略。我的傾向是說可能應該有一個ValuePolicy而不是將它與KeyPolicy分組,但這不是在這裏也不在那裏。

namespace hash { 
namespace detail { 

    template< 
      typename Key 
      , typename Value 
      , typename KeyGetter 
      , typename KeyComparator> 
     class KeyPolicy { 
     public: 
      typedef Key key_t; 
      typedef Value value_t; 
      typedef KeyGetter get_t; 
      typedef KeyComparator compare_t; 
     }; 

}} // hash detail 

HashTable是無效的,除非它具有相同的KeyPolicy作爲rehast等,所以不要給它一個。

namespace hash { 
namespace detail { 

    template<typename RehashPolicy> 
     class HashTableImpl { 
     public: 
      typedef RehashPolicy rehash_p; 
      typedef typename rehash_p::key_policy_t::key_t key_t; 
      // typedef ... 
     }; 

    // this doesn't have a specific name, its anything. 
    template<typename KeyPolicy> 
     class SomeRehashPolicy { 
     public: 
      typedef KeyPolicy key_policy_t; 
     }; 

}} // hash detail 

顯然你可以添加你想要的任何typedefs。如果我在代碼審查是一個堅持己見的人我可能會問的東西像rehash_pkey_policy_t是私有的。他們真的是實施細節。你試圖保護的實際不變是key_t等。

也許我在禮儀的合理範圍之外,但我的誠實觀點是,所有這些配置只對寫它的人有意思。不是你,沒有人使用它。所以我只會公開HashTable配置或兩個人實際上要使用的配置。

namespace hash { 

    struct stub {}; // sorry, I'm lazy 

    template<typename Key, typename Value> 
     class HashTable { 
     private: 
      typedef typename detail::KeyPolicy<Key, Value, stub, stub> key_p; 
      typedef typename detail::SomeRehashPolicy<key_p> rehash_p; 
      typedef typename detail::HashTableImpl<rehash_p> impl_t; 
     public: 
      typedef typename impl_t::key_t key_t; 
     }; 

} // hash 

int main(int argc, char ** argv) { 
    hash::HashTable<int, double> hash_table; 
    return 0; 
} 

很多細節未填寫很明顯,但你的想法。

+0

。因爲我正在編寫自己的Hashtable,所以我對它也很感興趣:)但是我同意,它增加了最終用戶的混亂,並可能使他們感到困惑(可能是我在路上)。參考任何未來的SOer,在上述實現中,除非使用基類優化,否則「細節」類將佔用額外的空間。 +1進行詳細解釋。 – Samaursa 2012-01-18 02:39:49

+0

@Samaursa最終用戶不必詳細處理任何事情,除非他們想要。您可以將其隱藏在完全不同的標題中,以便最終用戶不必知道。基類是「優化」任何東西,它增加了額外的虛擬呼叫。如果這對你更有意義,那麼維護起來就更簡單了。我會說這很有價值。 – 2012-01-18 15:32:06

+0

在這種情況下,'Hashtable'是用戶不會直接使用的東西。他們將使用一個關聯容器,比如'hash_map',它將使用'Hashtable'作爲其邏輯。所以基本上,所有這些靈活性都是爲了圖書館作者(現在我)。所以是的,我將主要「隱藏」細節,並像你指出的那樣公開一個'hash_map'類。至於基類優化,我沒有仔細閱讀。你正在聲明'typedef's,我認爲那裏有一個變量。 – Samaursa 2012-01-18 16:07:06