2010-12-15 21 views
10

Unnötig mehr als der folgenden Code zu sagen:Warum funktioniert ostream_iterator nicht wie erwartet?

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

Antwort

9

das Problem ist, dass der Name Lookup Ihrefinden nicht. Der Code, der versucht, das operator<< aufzurufen, befindet sich irgendwo innerhalb der , die sich in dem Namespace std befindet. Die Namenssuche sucht nach der richtigen Funktion in ostream_iterator<> und dem std Namensraum; Die argumentabhängige Suche hilft hier nicht, da sich beide Parameter ebenfalls im Namespace std befinden.

Also, mein Vorschlag ist (1) entweder Ihren Operator in namespace std { } zu wickeln, aber das ist UB, IIRC. Oder (2) Erstellen Sie eine Struktur, die von 10 erbt, um einen neuen Typ in Ihrem Namespace zu definieren, und verwenden Sie die ADL, um Ihre operator<<() zu finden.

UPDATE:

Mein dritte Vorschlag ist, eine benutzerdefinierte Manipulator zu verwenden, um das Paar zu drucken.

Was meinen zweiten Vorschlag, wenn Sie C++ 11 verwenden können, sollten von std::pair vererben leicht (ungetestet):

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

Wenn Sie nicht C 11 ++ verwenden können, dann schlage ich eine mit benutzerdefinierter Manipulator

+0

Können Sie erläutern, wie Ihre spätere Lösung funktioniert? –

+0

@ IvanZ.Siu: Siehe mein Update. – wilx

9

Dies ist ein häufiges Problem: in einem Wort, wird Ihre operator<< nicht, wenn gesehen std::ostream_iterator instanziieren.

Während der Instanziierung versucht die Namenssuche, einen operator<< im Namespace std zu finden. Es werden Kandidaten gefunden, so dass keine anderen Namespaces (und insbesondere nicht der globale Namespace) berücksichtigt werden. Dann kommt die Überladungsauflösung ins Spiel: Keine der Überladungen stimmt mit dem Argumenttyp überein, daher schlägt die Kompilierung fehl. Beachten Sie, dass die argumentabhängige Suche keine Hilfe ist, da std::pair auch im Namespace std ist.

Sie haben zwei Lösungen:

  • Schliessen Sie Ihren operator<< in namespace std { }, obwohl Sie, dass wissen sollte dies nach dem Standard (17.4.3.1)
  • std::copy für diese Aufgabe und Verwendung Vermeiden illegal std::for_each (entweder mit einem ‚altmodischen‘ Funktor oder Lambda)
+0

@icecrime, Ist das ein Fehler des C++ - Standards? Oder gibt es Gründe dafür? – xmllmx

+0

@xmllmx: das ist nur die Art, wie Namespaces funktionieren, ich glaube nicht, dass es ein Defekt ist – icecrime

+0

@icecrime, mir ist klar, jetzt. – xmllmx

Verwandte Themen