開始的第一方案的查詢時間達到了O(n),我們認為在類的數量比較少的時候是可行的。在進入了第二方案的時候,我們讓查詢速度時間縮短到了O(log(n)),如果我們要在這裡更進一步的話,那就應該是O(1)了。在這裡我們就繼續推出這個所謂的常數時間方案。
在第二方案的時候,我們需要對數時間的比較來得到答案,如果是常數時間,那必須摒棄這種比較。參照前面的思路繼續往下,前面的map如果改成hashtable應該就可以了,每次對key通用運算就得到了對應value(就是函數或者functor)而這裡的key就是兩個型別參數組成的pair。但是Hashtable帶來了一定的複雜性和不穩定性。這裡大名鼎鼎的Alex給出的更直接穩定的方案就是直接把每個類都添加進一個index,通過2個index在二維數組中找到對應的處理函數(或者Functor)。這裡有一張文中的:
可以看到如果以後的處理函數是Rectangle,Screen的話,我們就找1,1這個點。類似的如果處理Circle在Printer上列印的話,我們就找3,4這個點對應的函數。這個用空間換取時間的方案就是通過std::vector來實現的,下面就是具體的實現:
#define IMPLEMENT_INDEXABLE_CLASS(SomeClass)<br />static int& GetClassIndexStatic()/<br />254<br />{/<br />static int index = -1;/<br />return index;/<br />}/<br />virtual int& GetClassIndex()/<br />{/<br />assert(typeid(*this) == typeid(SomeClass));/<br />return GetClassIndexStatic();/<br />}<br />template<br /><<br />class BaseLhs,<br />class BaseRhs = BaseLhs,<br />typename ResultType = void,<br />typename CallbackType = ResultType (*)(BaseLhs&, BaseRhs&)<br />><br />class BasicFastDispatcher<br />{<br />typedef std::vector<CallbackType> Row;<br />typedef std::vector<Row> Matrix;<br />Matrix callbacks_;<br />int columns_;<br />public:<br />BasicFastDispatcher() : columns_(0) {}<br />template <class SomeLhs, SomeRhs><br />void Add(CallbackType pFun)<br />{<br />int& idxLhs = SomeLhs::GetClassIndexStatic();<br />if (idxLhs < 0)<br />{<br />callbacks_.push_back(Row());<br />idxLhs = callbacks_.size() - 1;<br />}<br />else if (callbacks_.size() <= idxLhs)<br />{<br />callbacks_.resize(idxLhs + 1);<br />}<br />Row& thisRow = callbacks_[idxLhs];<br />int& idxRhs = SomeRhs::GetClassIndexStatic();<br />if (idxRhs < 0)<br />{<br />thisRow.resize(++columns_);<br />idxRhs = thisRow.size() - 1;<br />}<br />else if (thisRow.size() <= idxRhs)<br />{<br />thisRow.resize(idxRhs + 1);<br />}<br />thisRow[idxRhs] = pFun;<br />}<br />ResultType Go(BaseLhs& lhs, BaseRhs& rhs)<br />{<br />int& idxLhs = lhs.GetClassIndex();<br />int& idxRhs = rhs.GetClassIndex();<br />if (idxLhs < 0 || idxRhs < 0 ||<br />idxLhs >= callbacks_.size() ||<br />idxRhs >= callbacks_[idxLhs].size() ||<br />callbacks_[idxLhs][idxRhs] == 0)<br />{<br />... error handling goes here ...<br />}<br />return callbacks_[idxLhs][idxRhs].callback_(lhs, rhs);<br />}<br />};<br />
類的index不是固定的,或者說並不是在TypeList中的index,因為我們這裡已經沒有TypeList了。現在需要主動需要植入每個class裡面,這也意味這原來非侵入式的平衡已經被打破了。每個類都需要申明這個宏。這裡的Matrix通過std::vector來組織,存放的具體內容就是CallbackType,當前這個BasicFastDispatcher類和原來的BasicDispatcher平行,也就是說可以通過Policy來進行替換,成為其他FnDispatcher的新的back end。在這裡的vector size的處理上有點小技巧,通過columns_來動態調整vector的size,而不是一上來就開出整個typelist長度的二維數組。同時也通過這個columns_來給classindex賦值。(注意這裡的GetClassIndexStatic函數返回的一直是int&)。還有一點就是出錯處理這裡沒有寫出來,但是不像原來的hatcher可以有個類,這裡都是對應的函數,所以一般我們會在這裡拋出一個異常。
Okay,我們就把所有的三個方案就介紹了一遍,這裡有一張圖涵蓋了對三種方式的特性的總結:
至此,我們對既有方案有一個全面的認識,從而為特定的case選擇的時候也有章可循了。