2010-12-15 11 views
10

Inutile dire che non più di quanto il seguente codice:Perché ostream_iterator non funziona come previsto?

#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)); 
} 

risposta

9

Il problema è che la ricerca del nome non trova il tuo operator<<(ostream& os, const PAIR& r). Il codice che tenta di richiamare lo operator<< si trova in qualche parte all'interno dello ostream_iterator<> che si trova all'interno dello spazio dei nomi std. La ricerca del nome cerca la funzione giusta all'interno di ostream_iterator<> e dello spazio dei nomi std; la ricerca dipendente dall'argomento non aiuta qui perché entrambi i parametri si trovano nello spazio dei nomi std.

Quindi, il mio suggerimento è (1) di avvolgere il tuo operatore in namespace std { }, ma questo è UB, IIRC. Oppure (2) creare una struct che eredita da std::pair per definire un nuovo tipo nel proprio spazio dei nomi e utilizzare l'ADL per trovare il numero operator<<().

UPDATE:

mio terzo suggerimento è quello di utilizzare un manipolatore personalizzato per stampare la coppia.

quanto riguarda il mio secondo suggerimento, se è possibile utilizzare C++ 11, che eredita da std::pair dovrebbe essere facile (non testata):

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

Se non è possibile utilizzare C++ 11, allora io suggerisco di usare un manipolatore personalizzato.

+0

Puoi approfondire come funziona la tua soluzione successiva? –

+0

@ IvanZ.Siu: vedere il mio aggiornamento. – wilx

9

Questo è un problema comune: in una parola, il tuo operator<< non si vede quando si crea un'istanza std::ostream_iterator.

Durante l'istanziazione, il nome cerca i tentativi di trovare uno operator<< nello spazio nomi std. I candidati verranno trovati, quindi nessun altro namespace sarà considerato (e, in particolare, non lo spazio dei nomi globale). Quindi, entra in gioco la risoluzione di sovraccarico: nessuno del sovraccarico corrisponde al tipo di argomento, quindi la compilazione fallisce. Si noti che la ricerca dipendente dall'argomento non è di alcun aiuto in questo caso poiché std::pair si trova anche nello spazio dei nomi std.

Avete due soluzioni:

  • Racchiudi il operator<< in namespace std { }, anche se si dovrebbe sapere che questo è illegale secondo lo standard (17.4.3.1)
  • Evitare std::copy per questo compito e l'uso std::for_each (con un funtore "old style" o lambda)
+0

@ icecrime, Si tratta di un difetto dello standard C++? O c'è qualche logica per questo? – xmllmx

+0

@xmllmx: è proprio così che funzionano gli spazi dei nomi, non penso sia un difetto – icecrime

+0

@ icecrime, ora sono chiaro. – xmllmx

Problemi correlati