2016-09-18 38 views
2

下面的代碼(令人吃驚地)不與任一g++clang++編譯由於不明確的呼叫BuildStream一個輸入。導入單個類成命名空間<code>bar::Rectangle</code>作爲實例<code>bar::BuildStream</code>時似乎要求有沒有功能名稱衝突的命名空間之間

#include <iostream> 
#include <sstream> 

namespace foo { 

struct Rectangle { double height, width; }; 
std::ostream& operator<<(std::ostream& os, const Rectangle& a) { return os; } 

inline void BuildStream(std::ostringstream& os) { } 

template<typename T, typename... Args> 
void BuildStream 
(std::ostringstream& os, const T& item, const Args& ...args) { 
    os << item; 
    BuildStream(os, args...); 
} 

} // namespace foo 

namespace bar { 

inline void BuildStream(std::ostringstream& os) { } 

template<typename T, typename... Args> 
void BuildStream 
(std::ostringstream& os, const T& item, const Args& ...args) { 
    os << item; 
    BuildStream(os, args...); 
} 

using Rectangle = foo::Rectangle; 

} // namespace bar 

int main(int argc, char* argv[]) { 
    std::ostringstream os; 
    bar::BuildStream(os, 1, 2); 
    bar::BuildStream(os, bar::Rectangle(), bar::Rectangle()); 
    return 0; 
} 

的不確定性似乎在暗示,一般來說,如果一個類從命名空間foo導入命名空間bar,則必須格外小心,以確保bar沒有功能相同功能foo名。這明顯引發了名稱空間的一些好處。是否有避免這種歧義的更細緻的方法?

上下文是foo是大型庫的名稱空間,而bar是消費者項目的名稱空間(並且在實踐中出現此問題)。

+0

你會得到同樣的錯誤,如果你:1.刪除「使用」,2通行證「富::矩形」從主。這是由於[參數依賴查找](http://stackoverflow.com/questions/8111677/what-is-argument-dependent-lookup-aka-adl-or-koenig-lookup)。也明確地從模板函數調用bar :: BuildStream()將修復編譯錯誤。 –

+0

感謝您提供參數相關查詢的鏈接;這是解釋這種(有點不幸的)行爲的恰當的細微討論。 –

回答

2

這裏的問題是依賴於參數的查找。 bar::Rectangle實際上是foo::Rectangle,所以對BuildStream(os,args...)的調用需要檢查foo's命名空間以及重載。

需要小心。您可以通過限定通話避免歧義:

template<typename T, typename... Args> 
    void BuildStream(std::ostringstream& os, const T& item, const Args& ...args) 
    { 
    os << item; 
    bar::BuildStream(os, args...); // qualified 
    } 
+0

這解釋了爲什麼會發生,但不告訴OP如何解決模糊問題。 – 1201ProgramAlarm

+0

@ 1201ProgramAlarm:同意。我增加了更多的答案。 –

+0

謝謝。我非常清楚如何解決這個問題。我正在尋找的是一個簡潔的解釋,並且依賴於參數的查找是它! –