предупреждение о неоднозначном для ofstream, но не для ostream. Какая разница?

это не важно. Но мне любопытно, когда появится это предупреждение. Мой реальный вопрос заключается в том, почему ostream и ofstream рассматриваются по-разному.

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

С этой простой структуры, компилятор видит, что int можно преобразовать в Test.

поэтому я получаю предупреждение с этим кодом:

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

, когда он видит os << t.y он не знает, хочу ли я нажать int под названием t.y, или я хочу преобразовать int в тест сначала, а потом толкай. Это кажется довольно странным, вы думаете, что он предпочел бы не преобразованную перегрузку 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&)

в любом случае, один из способов решить эту проблему-отметить конструктор в тесте как explicit. Я могу жить с этим. Но самое странное, что если ofstream заменяется ostream, то предупреждение исчезнет. Есть идеи почему?

2 ответов


как предупреждение говорит вам, что с ofstream обе интерпретации требуют преобразования:

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

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

если вы используете ostream& напрямую, то int-устного перевода требует нет преобразование и, следовательно, является предпочтительным.


когда вы называете

os << t.y;

у вас есть 2 кандидата:

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

и

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

нет такого кандидата как

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

согласно правилам разрешения перегрузки, ни 1, ни 2 не лучше для вашего звонка. Отсюда и предупреждение. В случае ostream, 1, очевидно, лучше подходит, потому что оба аргумента точно совпадают.

лучшее решение-пойти с std::ostream. Зачем вам нужно перегружать специально для file потоки. Что делать, если вам нужно передать его в строку? Перегрузка оператора выходного потока для std::ostream (или даже шаблонная версия std::basic_ostream) и пусть компилятор обрабатывает остальное.