Zunächst betrachtet der Compiler die Typen links und rechts von <<. std::coutist vom Typ std::ostream, das String-Literal ist vom Typ Array von 15const char . Da die linke vom Klassentyp ist, wird nach einer Funktion mit dem Namen gesucht operator<<. Die Frage ist, wo wird es aussehen?
Die Suche nach diesem Namen operator<<ist eine sogenannte unqualifizierte Suche, da der Funktionsname nicht wie qualifiziert ist std::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 Signatur
template<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 zugeordnet std::cout, daher wird diese Funktion gefunden.
std::ostreamist nur ein typedef für std::basic_ostream<char, std::char_traits<char>>, und das Array von 15const char kann implizit in a konvertiert werden char 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);
}
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);
}
}
zu:
namespace my_namespace
{
struct X
{
void operator<<(int) {}
void search();
};
void operator<<(X, double) {}
void X::search() {
*this << 2.5;
}
}