分類
C++中,由於引入了名字空間和類域,函式所在域就由原來的全局域變成如下幾個作用域 。
(1)類域(函式作為某個類的成員函式(靜態或非靜態))
(2)名字空間域
(3)全局域
上面的函式調用,第一個f就是無限定域的函式調用,第二個則限定了在名字空間N裡面,也是說使用了完全限定名。而Koenig查找,它的規則就是當編譯器對無限定域的函式調用進行名字查找時,除了當前名字空間域以外,也會把函式參數類型所處的名字空間加入查找的範圍。
套用示例
考察如下代碼。
我們通常都會寫如上的代碼,使用operator<<列印對象的狀態,但是ostream& operator<<(ostream& out, const KoenigArg& kArg)的定義是處於名字空間Koenig,為什麼編譯器在解析main函式(全局域)裡面的operator<<調用時,它能夠正確定位到Koenig名字空間裡面的operator<<?這是因為根據Koenig查找規則,編譯器需要把參數類型KoenigArg所在的名字空間Koenig也加入對operator<<調用的名字查找範圍中。
如果沒有Koenig查找規則,我們就無法直接寫cout<<karg;,而是需要寫類似Koenig::operator<<(std::cout, karg);這樣的代碼(使用完全限定名)。嗯,即不直觀也不方便是嗎?更重要的是如果我們寫的是模版代碼,在模版參數還沒有實例化之前,我們根本就不知道參數所處的名字空間,比如:
很顯然,你的模版代碼根本無法確認T是來自那個名字空間,直到編譯器對模版實例化(print(karg); 被調用)。
異議
對Koenig查找規則的一個異議是,由於Koenig查找規則的存在,處於某個名字空間的函式調用的重載決議會受到另外一個名字空間的自由函式所影響,僅僅是由於它使用了另外一個名字空間的類型作為參數。在這樣的規則下,名字空間看起來不像我們一般所想像的那樣是完全封閉和獨立的。
我們應該怎么解釋這樣的異議呢?這樣隱諱的影響或者依賴性是合理的嗎?Herb認為,如果我們把另外一個名字空間的自由函式(非類成員函式)也看作是它所涉及的類型的接口的一部分,很顯然,它應該參與這樣的重載決議,這樣的跨越名字空間的影響是合理的。從而導出了Herb在傳統類定義之上的一個更詳細和完整的解釋(請參考Exceptional C++, Item 32)。
關於Koenig查找,我們該說的都說了嗎?其實未然,之前所描述的只是Koenig查找一般可能發生的狀況,當Koenig查找規則和C++原來的Ordinal Lookup(OL,順序查找規則)混合在一起的時候,它們之間的組合所產生的狀況要比之前的例子複雜的多。