2010-12-15 67 views
10

Không cần phải nói nhiều hơn bất kỳ đoạn mã sau:Tại sao ostream_iterator không hoạt động như mong đợi?

#include <utility> 
#include <vector> 
#include <iostream> 
#include <iterator> 

using namespace std; 

typedef pair<char, char> PAIR; 

ostream& operator <<(ostream& os, const PAIR& r) 
{ 
    return os << r.first; 
} 

int main() 
{ 
    vector<PAIR> coll; 

    cout << coll[0]; // OK. 

    // The following line will cause a compilation error! Why??? 
    copy(coll.begin(), coll.end(), ostream_iterator<PAIR>(cout)); 
} 

Trả lời

9

Vấn đề là tra cứu tên không tìm thấycủa bạn. Mã tìm cách gọi operator<< nằm ở đâu đó bên trong số ostream_iterator<> nằm bên trong không gian tên std. Tra cứu tên nhìn xung quanh cho đúng chức năng bên trong ostream_iterator<> và không gian tên std; tra cứu phụ thuộc đối số không giúp được ở đây vì cả hai tham số đều nằm trong không gian tên std.

Vì vậy, đề xuất của tôi là (1) hoặc là đưa nhà điều hành của bạn vào namespace std { }, nhưng đó là UB, IIRC. Hoặc (2) tạo cấu trúc kế thừa từ std::pair để xác định loại mới trong không gian tên của bạn và sử dụng ADL để tìm số operator<<() của bạn.

UPDATE:

gợi ý thứ 3 của tôi là sử dụng một thao túng tùy chỉnh để in ra các cặp.

Đối với đề nghị thứ 2 của tôi, nếu bạn có thể sử dụng C++ 11, kế thừa từ std::pair nên dễ (chưa được kiểm tra):

struct PAIR : std::pair 
{ 
    using std::pair::pair; 
}; 

Nếu bạn không thể sử dụng C++ 11, sau đó tôi đề nghị sử dụng một tùy chỉnh thao túng.

+0

Bạn có thể giải thích cách hoạt động của giải pháp sau này không? –

+0

@ IvanZ.Siu: Xem cập nhật của tôi. – wilx

9

Đây là một vấn đề thường gặp: trong một từ, operator<< của bạn không được nhìn thấy khi instantiating std::ostream_iterator.

Trong quá trình khởi tạo, tra cứu tên tìm cách tìm một số operator<< trong không gian tên std. Ứng cử viên sẽ được tìm thấy, do đó không có không gian tên nào khác sẽ được xem xét (và đặc biệt, không phải là không gian tên chung). Sau đó, độ phân giải quá tải đi vào: không có quá tải nào phù hợp với loại đối số, vì vậy quá trình biên dịch không thành công. Lưu ý rằng tra cứu phụ thuộc đối số không phải là bất kỳ trợ giúp nào ở đây là std::pair cũng nằm trong không gian tên std.

Bạn có hai giải pháp:

  • Kèm theo của bạn operator<< trong namespace std { }, mặc dù bạn nên biết rằng này là bất hợp pháp theo tiêu chuẩn (17.4.3.1)
  • Tránh std::copy cho nhiệm vụ này và sử dụng std::for_each (hoặc với một functor 'kiểu cũ' hoặc lambda)
+0

@icecrime, Đây có phải là lỗi của tiêu chuẩn C++ không? Hay có lý do nào cho điều đó? – xmllmx

+0

@xmllmx: đó chỉ là cách không gian tên hoạt động, tôi không nghĩ đó là lỗi – icecrime

+0

@icecrime, giờ tôi đã rõ. – xmllmx

Các vấn đề liên quan