2010-12-15 7 views
10

No hace falta decir más de lo que el siguiente código:¿Por qué ostream_iterator no funciona como se esperaba?

#include <utility> 
#include <vector> 
#include <iostream> 
#include <iterator> 

using namespace std; 

typedef pair<char, char> PAIR; 

ostream& operator <<(ostream& os, const PAIR& r) 
{ 
    return os << r.first; 
} 

int main() 
{ 
    vector<PAIR> coll; 

    cout << coll[0]; // OK. 

    // The following line will cause a compilation error! Why??? 
    copy(coll.begin(), coll.end(), ostream_iterator<PAIR>(cout)); 
} 

Respuesta

9

El problema es que la búsqueda de nombre no encuentra su operator<<(ostream& os, const PAIR& r). El código que intenta invocar el operator<< está en algún lugar dentro del ostream_iterator<> que está dentro del espacio de nombre std. La búsqueda de nombres busca la función correcta dentro de ostream_iterator<> y el espacio de nombres std; la búsqueda dependiente del argumento no ayuda aquí porque ambos parámetros están también en el espacio de nombre std.

Por lo tanto, mi sugerencia es (1) envolver su operador en namespace std { }, pero eso es UB, IIRC. O bien, (2) cree una estructura que hereda de std::pair para definir un nuevo tipo en su espacio de nombres y utilizando la ADL para buscar su operator<<().

ACTUALIZACIÓN:

Mi tercera sugerencia es usar un manipulador personalizada para imprimir el par.

En cuanto a mi segunda sugerencia, si se puede usar C++ 11, heredando de std::pair debe ser fácil (no probado):

struct PAIR : std::pair 
{ 
    using std::pair::pair; 
}; 

Si no puede utilizar C++ 11, entonces se sugiere emplear una manipulador personalizado

+0

¿Puede explicar cómo funciona su solución posterior? –

+0

@ IvanZ.Siu: mira mi actualización. – wilx

9

Este es un problema común: en una palabra, su operator<< no se ve cuando una instancia de std::ostream_iterator.

Durante la creación de instancias, la búsqueda de nombres intenta encontrar un operator<< en el espacio de nombres std. Se encontrarán los candidatos, por lo que no se considerarán otros espacios de nombres (y, particularmente, no el espacio de nombres global). Entonces, la resolución de sobrecarga entra en juego: ninguna de las sobrecargas coincide con el tipo de argumento, por lo que la compilación falla. Tenga en cuenta que la búsqueda dependiente del argumento no sirve de nada, ya que std::pair también se encuentra en el espacio de nombres std.

Usted tiene dos soluciones:

  • incluya su operator<< en namespace std { }, aunque debe saber que esto es ilegal de acuerdo con la norma (17.4.3.1)
  • Evitar std::copy para esta tarea y su uso std::for_each (ya sea con un functor "anticuado" o lambda)
+0

@icecrime, ¿Esto es un defecto del estándar C++? ¿O hay alguna razón para eso? – xmllmx

+0

@xmllmx: así es como funcionan los espacios de nombres, no creo que sea un defecto – icecrime

+0

@icecrime, estoy claro ahora. – xmllmx

Cuestiones relacionadas