2013-02-19 70 views
3

我試圖使用stl copy()在地圖中打印鍵值對。代碼如下:使用模板參數重載運算符<<時編譯錯誤

#include <iterator> 
#include <iostream> 
#include <algorithm> 
#include <map> 

using namespace std; 
//compile error if I comment out "namespace std" 
namespace std {  
template<typename F, typename S> 
ostream& operator<<(ostream& os, const pair<F,S>& p) { 
    return os << p.first << "\t" << p.second << endl; 
} 
} 

int main() { 
    map<int, int> m; 
    fill_n(inserter(m, m.begin()), 10, make_pair(90,120)); 
    copy(m.begin(), m.end(), ostream_iterator<pair<int,int> >(cout,"\n")); 
} 

我想重載operator < <。問題是代碼不會編譯,除非我將重載運算符< <的定義與namespace std一起包圍。我認爲這是由於C++的名稱查找機制,我仍然無法理解。即使我定義這樣的非模板版本:

它仍然不會編譯。誰能解釋爲什麼?

+0

[錯誤示例](http://liveworkspace.org/code/3MJn1M$1) – 2013-02-19 02:41:41

回答

2

您的問題與argument-dependent name lookup(ADL)。編譯器在namespace std中搜索operator<<的實現,因爲ostreampair都在該名稱空間中。你應該從正確的命名空間轉發到operator<<包裝:

template<class T> 
struct ostreamer { 
    ostreamer(const T& value) : reference(value) {} 
    const T& reference; 
    friend ostream& operator<<(ostream& stream, const ostreamer& value) { 
    return stream << value.reference; 
    } 
}; 

就用ostream_iterator<ostreamer<pair<const int, int>>>代替ostream_iterator<pair<int, int>>。請注意,由於ostreamer按引用而非按值存儲,因此不能再依賴於從pair<const int, int>pair<int, int>的隱式轉換。您可以將ostreamer更改爲按價值存儲,但實際上,它沒有任何開銷,我認爲無論如何都應該明確一點。

+0

其實它只是在std命名空間中重載東西是安全的,如果它涉及用戶定義的類型(我會試着找到一個稍後參考規範)。因爲它既不是OP,也不是你的榜樣。 – John5342 2013-02-19 06:41:00

+0

@Jon感謝您的回覆!這是否意味着編譯器只查找std命名空間中的函數,而沒有其他地方?現在的翻譯單位等其他地方呢? – rialmat 2013-02-19 08:56:53

+0

@ John5342我想知道「實際上,只有在涉及用戶定義類型的情況下,才能在std命名空間中重載東西是安全的」。我認爲這裏的'pair'構造有點像用戶定義的類型,運算符<<不知道如何輸出一個對,就像它不知道如何輸出用戶定義類型一樣。 – rialmat 2013-02-19 09:04:11