2012-07-13 19 views
3

我一直在閱讀Josuttis模板書,並一直試圖將我的頭放在ADL周圍。他說:「ADL通過在名稱空間和類中查找名稱」與「調用參數的類型」相關聯。我只是想看看它是如何工作在一個類中查找名稱。下面我舉了一個我的測試例子。我看到它是如何在命名空間中查找名稱的。參數相關查找是否僅搜索名稱空間或類?

class bryan_ns { 
    public: 
    class bryan { 
    public: 
     enum E { e1 }; 
     static void bryan_test() { std::cout << __PRETTY_FUNCTION__ << std::endl; } 
    }; 

    void f(bryan::E) { std::cout << __PRETTY_FUNCTION__ << std::endl; } 
}; 

void f(int) 
{ 
    std::cout << "::f(int) called\n"; 
} 


int main() 
{ 
    f(bryan_ns::bryan::e1); // calls ::f(int) 
} 

但是,如果我改變bryan_ns一個命名空間像這樣:

namespace bryan_ns { 
    public: 
    class bryan { 
    public: 
     enum E { e1 }; 
     static void bryan_test() { std::cout << __PRETTY_FUNCTION__ << std::endl; } 
    }; 

    void f(bryan::E) { std::cout << __PRETTY_FUNCTION__ << std::endl; } 
}; 

void f(int) 
{ 
    std::cout << "::f(int) called\n"; 
} 


int main() 
{ 
    f(bryan_ns::bryan::e1); // calls bryan_ns::f(bryan::E) 
} 

回答

7

ADL將在封閉的名稱空間中查找類型,並且也在的類型中。最好的例子是在類型中定義友元函數:

namespace X { 
class test { 
    friend void f(test) { std::cout << "test" << std::endl; } 
}; 
} 
int main() { 
    X::test t; 
    f(t); 
} 

f(t)呼叫會發現X::f它的聲明僅僅是類型test內可用。這是friend函數聲明的一個鮮爲人知的特性:它們聲明一個名稱空間級別的函數,但僅在該類型中提供聲明。一個簡單的測試來驗證此行爲:

namespace X { 
    class test { 
     friend void f(test); 
    }; 
    //void f(test);   // [1] 
} 
void X::f(X::test) {}  // [2] 
int main() { 
    X::test t; 
    f(t);      // [3] 
} 

定義 [2]將觸發一個編譯錯誤,因爲你只能定義已經被宣佈爲功能,併爲[2]在名稱空間X之外,該定義不起到自我聲明的作用(如果您在其所在的名稱空間內定義了一個函數,那麼該定義也是一個聲明,但在這種情況下不是)。如果我們取消註釋[1],錯誤將消失。或者,如果我們評論[2],代碼將會編譯,表明對於[3]中的調用,ADL已經在類中找到了聲明。

+0

非常感謝,我非常感謝你的幫助。你幫助我終於明白這一點。 – 2012-07-13 21:09:27

0

在第一個例子,是bryan_ns::f非靜態成員函數。在main中的表達式沒有.->成員操作符,所以它顯然不是成員函數調用,並且bryan_ns::f不是可行的函數。

+0

更改爲靜態不會修復它:) – 2012-07-13 02:42:41

+0

'bryan_ns :: f'不是成員函數 – Oktalist 2013-05-10 21:25:11

+0

原始帖子中有兩個程序。在第一個程序中,'f'是一個成員函數。第二,'f'不是一個成員函數。 – aschepler 2013-05-11 00:02:15

相關問題