2011-12-19 11 views
7

Esto no es importante. Pero tengo curiosidad sobre cuándo aparece esta advertencia. Mi verdadera pregunta es por qué ostream y ofstream se tratan de manera diferente.advertencia acerca de ambiguo para ofstream, pero no para ostream. ¿Cual es la diferencia?

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

Con esta sencilla estructura, el compilador ve que un int se puede convertir en un Test.

Por lo tanto, recibo una advertencia con este código:

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

Cuando se ve os << t.y que no sabe si quiero empujar el int llamado Ty, o si quiero convertir el int a una Pruebe primero y luego empújelo. Esto parece bastante raro, pensarías que preferiría la sobrecarga int no convertida 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&) 

De todos modos, una manera de resolver esto es para marcar el constructor en la prueba como explicit. Puedo vivir con ello. Pero lo extraño es que si ofstream se reemplaza por ostream, entonces la advertencia desaparece. ¿Alguna idea de por qué?

Respuesta

5

A medida que la advertencia que le dice, con ofstream ambas interpretaciones requieren conversiones:

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

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

Si utiliza ostream& directamente, a continuación, el int -inte rpretation requiere no conversión y, por lo tanto, es preferible.

+0

Eso tiene mucho sentido.Pero dado que ofstream hereda de ostream, pensarías que tal conversión sería mucho más natural. ofstream hereda 'operator << (int)' de ostream. Hubiera pensado que un elenco así sería muy preferido por el estándar. –

7

Cuando se llama a

os << t.y; 

tiene 2 candidatos:

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

y

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

no hay un candidato como

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

De acuerdo con las reglas de resolución de sobrecarga, ni 1 ni 2 son mejores para su llamada. De ahí la advertencia. En el caso de ostream, 1 es obviamente una mejor coincidencia, porque ambos argumentos coinciden exactamente.

La mejor solución es ir con std::ostream. ¿Por qué necesitaría sobrecargar específicamente para las transmisiones de archivos? ¿Qué pasa si necesitas transmitirlo en una cadena? Sobrecarga el operador de flujo de salida para std::ostream (o incluso una versión con plantilla de std::basic_ostream) y deja que el compilador maneje el resto.

+0

Me llevó unos 10 segundos detectar la diferencia ('* o * stream' contra' * of * stream') entre los ejemplos 1 y 3 ... –

Cuestiones relacionadas