Ambiguity warning for stream, but not for ostream. What's the difference?

It does not matter. But I'm curious when this warning appears. My real question is why ostream and stream are handled differently.

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

With this simple structure, the compiler sees that int can be converted to Test .

Therefore, I get a warning with this code:

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

When he sees os << ty , he does not know if I want to press int called ty, or I want to convert int to Test first and then click it. This seems rather strange, you would think that he would prefer the unprocessed overload of int 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&) 

In any case, one way to solve this problem is to mark the constructor in Test as explicit . I can live with it. But it is strange that if ofstream is replaced by ostream , then the warning goes away. Any idea why?

+7
source share
2 answers

As warns you, with ofstream both interpretations require transformations:

  • ofstream& -> ostream& in static_cast<ostream&>(os) << ty ,

  • int -> Test in os << static_cast<Test>(ty)

If you use ostream& directly, then int interpretation does not require conversion and, therefore, is preferred.

+5
source

When you call

 os << ty; 

you have 2 candidates:

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

and

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

There is no such candidate as

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

In accordance with the rules for resolving congestion, neither 2 nor 2 is better for your call. Hence the warning. In the case of ostream 1, obviously the best match is because both arguments are exactly the same.

The best solution is to go with std::ostream . Why do you need to overload specifically for file streams. What if you need to pass it to a string? The overload stream operator for std::ostream (or even the templatized version of std::basic_ostream ), and let the compiler handle the rest.

+7
source

All Articles