Geschichte der Frage: ADL (Argument Dependent Lookup), auch bekannt als Koenig Lookup, wurde erstmals in C++ eingeführt, um die Überladung von Operatoren zu unterstützen (insbesondere operator<< und operator>> für benutzerdefinierte Typen). Ziel ist es, Funktionen korrekt zu finden, wenn Namensräume und benutzerdefinierte Typen vermischt werden.
Problem: Der Standardmechanismus zur Funktionssuche kann eine Funktion "übersehen", wenn sie in einem anderen Namensraum als dem Aufrufpunkt deklariert ist. ADL löst dieses Problem: Der Compiler berücksichtigt den Namensraum der Argumenttypen der Funktion, um die Namen aufzulösen. Dieser Mechanismus kann jedoch manchmal zu unerwarteten Überladungsentscheidungen oder Mehrdeutigkeiten führen.
Lösung: Wenn eine Funktion aufgerufen wird, deren Argumente Objekte aus benutzerdefinierten Namensräumen sind, sucht der Compiler nach geeigneten überladenen Funktionen nicht nur im aktuellen Gültigkeitsbereich, sondern auch in allen Namensräumen, die mit den Argumenttypen verknüpft sind.
Beispielcode:
namespace lib { struct Widget {}; void do_something(const Widget&) { std::cout << "Widget" << std::endl; } } using lib::Widget; void call(const Widget& w) { do_something(w); // do_something wird über ADL gefunden }
Wichtige Merkmale:
Wenn eine Funktion mit demselben Namen in zwei Namensräumen deklariert wird und ein Objekt des zweiten übergeben wird, welche wird aufgerufen?
Die Funktion aus dem Namensraum des Arguments, wenn sie für die Argumente geeignet ist, wird dank ADL gewählt:
namespace A { struct S {}; void f(const S&) { std::cout << "A!"; } } namespace B { struct S {}; void f(const S&) { std::cout << "B!"; } } A::S a; B::S b; f(a); // ruft A::f über ADL auf f(b); // ruft B::f über ADL auf
Funktioniert ADL mit Template-Funktionen?
Ja, wenn die Template-Funktion in einem Namensraum definiert ist, der mit dem Typ des Arguments übereinstimmt, wird ADL sie beim Aufruf mit diesem Typ finden.
Wird ADL für Funktionszeiger funktionieren?
Nein, ADL wird nicht angewendet, wenn ein Zeiger auf eine Funktion erhalten wird (z.B. beim Abrufen ihrer Adresse). Nur bei direktem Aufruf der Funktion.
Das Projekt hat mehrere externe Bibliotheken eingebunden, in denen in jedem Namensraum eine eigene print() existierte. Im Hauptcode wurde print() mit Objekten unterschiedlicher Klassen verwendet. Wegen ADL begann der Compiler, die Funktion aus dem falschen Namensraum "auszuwählen".
Vorteile:
Nachteile:
Verwendung eines qualifizierten Aufrufs (explizite Angabe des Namensraums):
lib::do_something(w); // Explizit!
Vorteile:
Nachteile: