2011-12-19 6 views
7

Điều này không quan trọng. Nhưng tôi rất tò mò khi cảnh báo này xuất hiện. Câu hỏi thực sự của tôi là tại sao ostream và ofstream lại được đối xử khác nhau.cảnh báo về sự mơ hồ đối với dòng suối, nhưng không cảnh báo về luồng xương. Có gì khác biệt?

struct Test { 
    int y; 
    Test(int k) : y(k) {} 
}; 

Với struct đơn giản này, trình biên dịch thấy rằng một int có thể được chuyển đổi sang một Test.

Do đó, tôi nhận được một cảnh báo với mã này:

std :: ofstream& operator<< (std :: ofstream& os, const Test& t) 
{ 
    os << t.y; 
    return os; 
} 

Khi nó thấy os << t.y nó không biết liệu tôi có muốn đẩy int gọi là ty, hoặc cho dù tôi muốn chuyển đổi int để một Kiểm tra trước và sau đó đẩy nó. Điều này có vẻ khá kỳ lạ, bạn nghĩ rằng nó muốn không quá tải int chuyển đổi ofstream& operator<< (ofstream &os, int).

g ++ (Ubuntu 4.4.3-4ubuntu5) 4.4.3:

template_expl.cpp: In function ‘std::ofstream& operator<<(std::ofstream&, const Test&)’: 
template_expl.cpp:15: warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second: 
/usr/include/c++/4.4/bits/ostream.tcc:105: note: candidate 1: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(int) [with _CharT = char, _Traits = std::char_traits<char>] 
template_expl.cpp:13: note: candidate 2: std::ofstream& operator<<(std::ofstream&, const Test&) 

Dù sao, có một cách để giải quyết này là để đánh dấu các nhà xây dựng trong thử nghiệm như explicit. Tôi có thể sống với điều đó. Nhưng điều kỳ lạ là nếu ofstream được thay thế bằng ostream, thì cảnh báo sẽ biến mất. Bất kỳ ý tưởng tại sao?

Trả lời

5

Như lời cảnh báo cho bạn biết, với ofstream cả giải thích yêu cầu chuyển đổi:

  1. ofstream& -> ostream& trong static_cast<ostream&>(os) << t.y,

  2. int -> Test trong os << static_cast<Test>(t.y)

Nếu bạn sử dụng ostream& trực tiếp, sau đó int -inte rpretation yêu cầu không chuyển đổi và do đó được ưu tiên.

+0

Điều đó có ý nghĩa rất nhiều.Nhưng cho rằng thừa kế của dòng chảy từ ostream, bạn sẽ nghĩ rằng một chuyển đổi như vậy sẽ tự nhiên hơn rất nhiều. ofstream thừa kế 'operator << (int)' từ ostream. Tôi đã nghĩ rằng một diễn viên như vậy sẽ rất được ưa thích bởi tiêu chuẩn. –

7

Khi bạn gọi

os << t.y; 

bạn có 2 ứng cử viên:

ostream& operator << (ostream&, int) //1 

ofstream& operator << (ofstream&, Test) //2 

Không có ứng cử viên như

ofstream& operator << (ofstream&, int) //3 

Theo các quy tắc về độ phân giải quá tải, cả 1 và 2 đều không tốt hơn cho cuộc gọi của bạn. Do đó cảnh báo. Trong trường hợp của ostream, 1 rõ ràng là một trận đấu tốt hơn, bởi vì cả hai đối số phù hợp chính xác.

Giải pháp tốt nhất là đi với std::ostream. Tại sao bạn cần phải quá tải cụ thể cho các luồng tệp. Điều gì sẽ xảy ra nếu bạn cần truyền trực tuyến chuỗi đó thành chuỗi? Quá tải nhà điều hành luồng đầu ra cho std::ostream (hoặc thậm chí một phiên bản templatized của std::basic_ostream) và để cho trình biên dịch xử lý phần còn lại.

+0

Mất khoảng 10 giây để phát hiện sự khác biệt ('* o * luồng' so với' * của * luồng') giữa ví dụ 1 và 3 ... –