2012-01-29 23 views
12

Hoy pensé que sería una buena idea para sobrecargar operator<< para las matrices de estilo C:operador de sobrecarga para las matrices <<

template<typename T, size_t N> 
std::ostream& operator<<(std::ostream& os, T(&a)[N]) 
{ 
    os << '{' << a[0]; 
    for (size_t i = 1; i < N; ++i) 
    { 
     os << ',' << ' ' << a[i]; 
    } 
    os << '}'; 
    return os; 
} 

int main() 
{ 
    int numbers[] = {2, 3, 5, 7, 11, 13, 17, 19}; 
    std::cout << numbers << '\n'; 
} 

De hecho, esta opción se imprime {2, 3, 5, 7, 11, 13, 17, 19} muy bien. Sin embargo, al proporcionar esa sobrecarga, ya no puedo imprimir cadenas literales:

std::cout << "hello world\n"; 

error: ambiguous overload for 'operator<<' in 'std::cout << "hello world\012"' 
note: candidates are: 

note: std::basic_ostream<_CharT, _Traits>::__ostream_type& 
std::basic_ostream<_CharT, _Traits>::operator<<(long int) [with _CharT = char, _ 
Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_ 
type = std::basic_ostream<char>] <near match> 

note: no known conversion for argument 1 from 'const char [13]' to 'long int' 

Esto es realmente desconcertante. ¿Por qué el compilador incluso considera la sobrecarga long int cuando no hay conversión de const char[13] a long int en primer lugar?

Las variaciones de este mensaje de error aparecen por long unsigned int, short int, short unsigned int, int, unsigned int, long long int y long long unsigned int.

(Otros candidatos son const void*, const char* y const _CharT*, y mi propia plantilla.)


He resuelto el problema al proporcionar la plantilla sólo para los tipos no-char:

template<typename T, size_t N> 
typename std::enable_if< 
    !std::is_same<typename std::remove_cv<T>::type, char>::value, 
std::ostream&>::type operator<<(std::ostream& os, T(&a)[N]) 

Pero Todavía estoy desconcertado por la pregunta de por qué el compilador consideró los tipos numéricos como candidatos.

Respuesta

3

La primera etapa de la resolución de sobrecarga es identificar las funciones viables, que son las que pueden aceptar la cantidad de argumentos proporcionados (ignorando por completo los tipos). (Véase, por ejemplo, 13.3.2 [over.match.viable]).

Luego se considera cualquier conversión necesaria para determinar cuál es la única función viable única.

En este caso, no existe tal mejor único (hay dos candidatos igualmente buenos).

El mensaje de error podría indicarle los dos casos ambiguos. Pero creo que están tratando de ser útiles al mostrar por qué todas las otras funciones viables se perdieron. Algunas veces esto es útil, cuando no puede entender por qué no se ha considerado la función que deseaba llamar.

Pero estoy de acuerdo que sobre todo es mucho ruido, especialmente para funciones como operator << o operator >> (o incluso operator []) que tienen muchas sobrecargas.

1

El compilador rechaza el programa correctamente. Creo que la clave es que su sobrecarga y ostream::operator<<(char const *) aparecen en el mensaje de error. Los integrales son probablemente una pista falsa ... puede reinterpret_cast un puntero (o un literal de cadena) a long int (§5.2.10/4), pero ciertamente no es una conversión estándar. Quizás el compilador solo intenta ser útil al darle más sobrecargas.

Dada su sobrecarga y el miembro ostream, la resolución de sobrecarga falla simplemente porque no hay una regla de precedencia para decidir entre ellos (§13.3.1.2). Por lo tanto, dado que la sobrecarga de miembro char const * es la única con la que puede entrar en conflicto, su corrección parece apropiada.

+0

'std :: ostream' es una referencia a una clase. – Mankarse

Cuestiones relacionadas