2014-06-24 47 views
2

我剛剛閱讀這篇文章:Fun with C++ namespaces 作者表示編譯器在遇到第一個時會停止查找重載,這裏使用命名空間。爲什麼編譯器在重載時停止名稱查找?

namespace A 
{ 
    void f(int x); // like our std::sqrt(double) 
} 

namespace B 
{ 
    struct S {}; // user-defined type with associated namespace B 

    void f(S); 
    void f(int, int); 

    void test1() 
    { 
     using namespace A; // using DIRECTIVE 
     f(1);    // ERROR namespace A is not considered because 
         //  B contains two overloads for 'f' 
     f(1,2);   // OK  B::f(int,int) 
     f(B::S());   // OK  B::f(S) 
    } 

    void test2() 
    { 
     using A::f; // using DECLARATION 
     f(1);  // OK  A::f(int) 
     f(1,2);  // ERROR A::f hides B::f(int,int) 
     f(B::S()); // OK  B::f(S) due to ADL! 
    } 
} 

namespace C 
{ 
    void test3() 
    { 
     using namespace A; // using DIRECTIVE 
     f(1);    // OK  A::f(int) 
     f(B::S());   // OK  B::f(S) due to ADL! 
    } 

    void test4() 
    { 
     using A::f; // using DECLARATION 
     f(1);  // OK  A::f(int) 
     f(B::S()); // OK  B::f(S) due to ADL! 
    } 
} 

爲什麼編譯器應該停止?編輯#1:這個問題確實是一個問題:標準爲什麼這麼說?

感謝您的所有答案!

+1

因爲標準是這樣說的嗎? – PlasmaHH

回答

4

遇到第一個

不,它不會停止「遇到第一個當」否則你找不到既B::f(int,int)B::f(S)當編譯器停止找過載。

它找到給定範圍內的所有重載(不僅僅是第一個),但不會在更遠的範圍看起來更遠。

這就像在C++中的所有名稱查找,如果你有一個全局變量稱爲var和一些功能也有一個局部變量叫var,使用功能中的名稱將引用局部變量。這樣做更有用,它更可能意味着使用附近聲明的變量,因爲它在相關的代碼中。

如果有人給你發了一封信,告訴你把它交給弗雷德,他站在幾米遠的地方,身上戴着一張標有「我是弗雷德」的徽章,你會不理他,到外面繼續尋找其他人世界上的人叫弗雷德?

+0

比喻好,易於理解。但是,作爲一名新手程序員,我希望編譯器能夠做一個完整的查找。直到我閱讀博客文章。有編譯器選項來發現這種情況,以便編譯器可以警告我嗎?或者更好的是,這個行爲的名稱是什麼,所以我可以谷歌...(名稱查找?) – Buni

+0

@Buni重載分辨率。 – 0x499602D2

+0

@ 0x499602D2,不,我會說名稱查找。重載解析一般是指決定哪幾個命名函數是最好的匹配,但你必須執行名稱查找來首先查找這些函數 –

1

使用A :: f隱藏了「f」的所有以前的定義。

您可以使用

void test2() 
    {  
     f(1,2);  // ERROR A::f hides B::f(int,int) 
     using A::f; // using DECLARATION 
     f(1);  // OK  A::f(int) 
     f(B::S()); // OK  B::f(S) due to ADL! 
    } 

void test2() 
    { 
     using A::f; // using DECLARATION 
     f(1);  // OK  A::f(int) 
     using B::f; 
     f(1,2);  // ERROR A::f hides B::f(int,int) 
     f(B::S()); // OK  B::f(S) due to ADL! 
    } 

最佳做法是調用

void test2() 
    { 
     A::f(1);  // OK  A::f(int) 
     B::f(1,2);  // ERROR A::f hides B::f(int,int) 
     B::f(B::S()); // OK  B::f(S) due to ADL! 
    } 

它明確提到使用哪種功能

+0

您可以修復評論。 – Jarod42

1

顯而易見的答案是:因爲標準是這樣說的。 標準說的原因,就是爲了讓你的程序更加健壯: 假設你寫你的類:

class MyClass : public SomeBase 
{ 
private: 
    void f(int); 
    void g() 
    { 
     f('x'); 
    } 
}; 

因爲它的立場,在g調用點,編譯器會發現 MyClass::f(int),並只有MyClass::f(int)。這可能是你想要的 。你不想要的是編譯器 突然開始發現SomeBase::f(char)如果有人碰巧加了它 。 (所以,至少,理由如此。)

最後:編譯器不是當它找到 找到一個符號時總是停止查找。例如,有ADL需要考慮。 而模板中的規則略有不同,具體取決於 該符號是否依賴。

+0

當'SomeBase'也有這樣的方法時,我希望編譯器選擇更專用的方法 - >'MyClass :: f(int)' – Buni

相關問題