Warum muss ich schreiben std::cout
und nicht auch std::<<
in eine Codezeile wie diese:
#include <iostream>
int main() {
std::cout << "Hello, world!";
return 0;
}
cout
kommt aus der std
Bibliothek und wird <<
normalerweise nicht zum Verschieben von Bits verwendet? Warum muss ich den Scope-Operator nicht ::
auch vorher schreiben <<
, da er auch mit einer anderen Bedeutung verwendet wird? Wie der Compiler weiß , dass nach std::cout
, <<
bedeutet eine andere Sache?
<<
das übrigens vollständig qualifizieren würden, müsste es so aussehenstd::operator<<(std::cout, "Hello, world!");
. Mit der C ++ - Syntax können Sie nicht schreibenstd::cout std::<< "Hello, world!"
, um dasselbe zu bedeuten, da der Begriff der Namespaces nicht für die Operatoren selbst gilt, sondern für die Namen der Funktionen, die sie überladen, z.operator<<
B.Antworten:
Zunächst betrachtet der Compiler die Typen links und rechts von
<<
.std::cout
ist vom Typstd::ostream
, das String-Literal ist vom Typ Array von 15const char
. Da die linke vom Klassentyp ist, wird nach einer Funktion mit dem Namen gesuchtoperator<<
. Die Frage ist, wo wird es aussehen?Die Suche nach diesem Namen
operator<<
ist eine sogenannte unqualifizierte Suche, da der Funktionsname nicht wie qualifiziert iststd::operator<<
. Die unqualifizierte Suche nach Funktionsnamen ruft eine argumentabhängige Suche auf. Die argumentabhängige Suche sucht in den Klassen und Namespaces, die den Argumenttypen zugeordnet sind.Wenn Sie einschließen
<iostream>
, eine freie Funktion der Signaturtemplate<typename traits> std::basic_ostream<char, traits>& operator<<(std::basic_ostream<char, traits>&, const char*);
wurde im Namespace deklariert
std
. Dieser Namespace ist dem Typ von zugeordnetstd::cout
, daher wird diese Funktion gefunden.std::ostream
ist nur ein typedef fürstd::basic_ostream<char, std::char_traits<char>>
, und das Array von 15const char
kann implizit in a konvertiert werdenchar const*
(zeigt auf das erste Element des Arrays). Daher kann diese Funktion mit den beiden Argumenttypen aufgerufen werden.Es gibt andere Überladungen von
operator<<
, aber die oben erwähnte Funktion passt am besten zu den Argumenttypen und der in diesem Fall ausgewählten.Ein einfaches Beispiel für eine argumentabhängige Suche:
namespace my_namespace { struct X {}; void find_me(X) {} } int main() { my_namespace::X x; find_me(x); // finds my_namespace::find_me because of the argument type }
NB Da diese Funktion ein Operator ist, ist die eigentliche Suche etwas komplexer. Es wird über eine qualifizierte Suche im Bereich des ersten Arguments (wenn es sich um einen Klassentyp handelt) nachgeschlagen, dh als Elementfunktion. Zusätzlich wird eine unqualifizierte Suche durchgeführt, wobei jedoch alle Elementfunktionen ignoriert werden. Das Ergebnis ist etwas anders, da die unqualifizierte Suche tatsächlich einer zweistufigen Prozedur ähnelt, bei der die argumentabhängige Suche der zweite Schritt ist. Wenn der erste Schritt eine Elementfunktion gefunden hat , wird der zweite Schritt nicht durchgeführt, dh Argument abhängige lookup wird nicht verwendet.
Vergleichen Sie:
namespace my_namespace { struct X { void find_me(X, int) {} void search(); }; void find_me(X, double) {} void X::search() { find_me(*this, 2.5); // only finds X::find_me(int) // pure unqualified lookup (1st step) finds the member function // argument-dependent lookup is not performed } }
zu:
namespace my_namespace { struct X { void operator<<(int) {} void search(); }; void operator<<(X, double) {} void X::search() { *this << 2.5; // find both because both steps are always performed // and overload resolution selects the free function } }
quelle
(find_me)(x)
. Ich weiß nicht, ob / wie das für die Operatorsyntax funktioniert.(operator<<)(std::cout, "Hello, world!")
. Live BeispielIm
std::cout << "Hello, world!"; //calls std:::operator <<
Dies wird mit der argumentabhängigen Namenssuche (ADL, auch bekannt als Koenig Lookup ) erreicht.
Wir haben zwar nur ein
std
Qualifikationsmerkmal, aber es gibt zwei Dinge, die sich aus demstd
Namespace ergebencout
<<
Ohne ADL (Koenig Lookup)
std::cout std:: << "Hello World" ;//this won't compile
Um es zu kompilieren, müssen wir es hässlichere Form verwenden
std::operator<<(std::cout, "Hello, world!");
Um solch eine hässliche Syntax zu vermeiden, müssen wir Koenig Lookup schätzen :)
quelle
Der Compiler erkennt, dass die Argumente für << ein std :: ostream-Objekt und eine Zeichenfolge sind, und kann daher die richtige Operator << -Definition basierend darauf finden.
Sie können sich die Argumenttypen eines Operators (oder wirklich jeder Funktion) als Teil seines Namens vorstellen.
quelle