依賴於實參的名字查詢是 C 程式設計語言中的名字查詢機制之一。英文為 argumentdependent lookup，因此縮寫為 ADL。ADL 依據函式呼叫中的的資料型別查詢未限定（unqualified）的函式名（或者函式模板名）。這也被稱作 克尼格查詢（Koenig lookup），雖然安德魯克尼格並不是它的發明者。 語義 依賴於實參的名字查詢的先決條件 如果通常的未限定（unqualified）名字查詢所產生的候選集包括下述情形，則不會啟動依賴於實參的名字查詢： 類成員宣告（此種情形僅指普通的類成員函式，不指類成員運算子函式） 塊作用域內的函式的宣告，不含 usingdeclaration 任何不是函式或者函式模板的宣告（例如函式物件或者另一個變數其名字與被查詢的函式名字衝突） 名稱空間與類的相關集合 函式呼叫表示式的每個實參的型別用於確定名稱空間與類的相關集合（associated set of namespaces and classes）並用於函式名字查詢：《C14 語言標準》3422 For each argument type T in the function call there is a set of zero or more associated namespaces and a set of zero or more associated classes to be considered The sets of namespaces and classes is determined entirely by the types of the function arguments and the namespace of any template template argument 基本型別（fundamental type）實參的名稱空間與類的相關集合為空。 類型別（class type，指 struct class union 型別） 相關集合包括 類型別自身 如果類型別是另一個類的成員，則那個包含了類型別的類； 該型別的所有的直接或間接基類； 該類型別的所有相關類的最內部包含名稱空間。 如果實參是類模板特化後得到的型別，除了應用類型別規則，還要包括下述規則提及的型別的相關名稱空間與類的集合： 型別模板形參（type template parameter）所對應的模板實參的型別，不包括非型別的模板形參、模板的模板形參； 模板的模板實參（template template argument）所在的名稱空間； 模板的模板實參所在的類（如果這個類包含了這個成員模板）。 對於列舉型別的實參，列舉型別所在的名稱空間；如果列舉型別是一個類的成員型別，則該類加入相關集合。 如果實參是型別 T 的指標或者是型別 T 的陣列的指標，則型別 T 的相關集合被加入該實參型別的相關集合。 如果實參是函式型別，那麼該函式的形參型別與函式返回值的型別的相關集合被加入到該實參型別的相關集合。 如果實參是類 X 的成員函式 F 的類成員函式指標，那麼該成員函式的形參型別、該成員函式返回值的型別、該成員函式所屬類 X 的相關集合都被加入到該實參型別的相關集合。 如果實參是類 X 的資料成員 T 的類資料成員指標，那麼該成員型別、該資料成員所屬類 X 的相關集合都被加入到該實參型別的相關集合。 如果實參是一套過載函式（或者函式模板）的名字或者取地址表示式 addressof expression，那麼過載集中的每個函式的相關集合都被加入到該實參型別的相關集合。 此外，如果過載集是 templateid 模板名字與模板實參 則所有的型別模板實參與模板的模板實參（不含非型別模板實參）的相關集合都被加入到該實參型別的相關集合。 如果相關集合中的任何名稱空間是內聯名稱空間（inline namespace） 則包含它的名稱空間被增加到相關集合中。 如果相關集合中的一個名稱空間直接包含了內聯名稱空間，則內聯名稱空間被增加到相關集合中。 相關名稱空間中的 usingdirectives 被忽略 通常的未限定查詢發現的結果與 ADL 查詢發現的結果應該合併，並遵從如下特別規則： 透過 ADL 查詢到的相關類內的友函式與函式模版是可見的 所有的名字，如果不是函式或者函式模版，將被忽略（不與變數名字衝突） 例子 一個簡單示例： namespace NS class A void f A int int main NSA a f a 0 calls NSf fa0 error NSf not considered parentheses prevent argumentdependent lookup 更為複雜、精緻的例子： namespace N2 struct DS namespace N1 struct S void operatorS templateint X void f S void fDS N2DS v namespace N2 struct DS N1S templateclass T void f T t void g N2DS sv fDS sv sv 的型別 N2DS 的基型別 N1S 所在的名稱空間 N1 的函式 N1fDS svsv 呼叫 N1SoperatorS 運算子成員函式 另一個示例： namespace N1 struct S templateint X void f S void bar S namespace N2 templateclass T void f T t void g N1S s bar s lookup N1bar f3s Syntax error unqualified lookup finds no f so it understands as arithematic expression f 3 N1f3s OK qualified lookup finds the template f N2f3s Error N2f does not take a nontype parameter N1f is not looked up because ADL only works with unqualified names using N2f f3s OK Unqualified lookup now finds N2f then ADL kicks in because this name is unqualified and finds N1f 關於內聯名稱空間的示例： namespace ADL inline namespace v101 下述程式碼中，名稱空間名字 v101 都可以忽略 class foo public class bar void func1 foobar v int i 101 int main ADLfoobar v1 func1 v1 lookup to ADLfunc1 介面 ADL 能查詢到的函式被認為是類的介面之一。標準模板庫的幾個 std 名稱空間的演算法使用未限定的 swap 呼叫。使用時，如果名字查詢沒找到其它結果，則使用 stdswap 函式；如果這些演算法使用第三方類，如 Foo，在另一個名稱空間中發現包含了 swap Foo Foo 則過載版的 swap 被優先使用。 C 標準程式庫常見模式是用 ADL 查詢程式宣告的過載運算子。例如，下述程式如果沒有 ADL 將無法編譯透過： includeiostream int main string hello Hello World where did operator come from stdcout hello stdendl 運算子 等價於呼叫函式 operator，但沒有給出 std 限定符。透過 ADL 查詢到函式 stdostream stdoperatorstdostream const char。 批評 ADL 使得類之外定義的函式就如同類的介面一樣被呼叫，這使得名稱空間不是過於嚴格。例如，C 標準模板庫使用未限定的 swap 呼叫，允許使用者定義自己的 swap 供標準模板庫的演算法使用。換句話說， stdswap a b 的效果可能相同與或不同於 using stdswap swap a b （其中 a 與 b 的型別是 NA）。因為如果 Nswap NA NA 存在，上述第二段程式碼將呼叫它，而上述第一段程式碼將不呼叫它。 參考文獻 外部連結 Argumentdependent lookup Whats In a Class The Interface Principle by Herb Sutter Namespaces and the Interface Principle by Herb Sutter Why I Hate Namespaces by Danny Kalev A Modest Proposal Fixing ADL revision 2 by Herb Sutter CategoryC