6

Hier ein Beispiel:Argument-dependent Nachschlag und Funktionsschablonen

#include <string> 
#include <algorithm> 
#include <memory> 

using std::string; 

int main() 
{ 
    string str = "This is a string"; 

    // ok: needn't using declaration, ADL works 
    auto it = find(str.begin(), str.end(), 'i'); 

    // error: why ADL doesn't work? 
    std::shared_ptr<string> sp = make_shared<string>(str); 
} 

Wenn ich dieses Programm zu kompilieren versucht, der Compiler beschwert:

error: no template named 'make_shared'; did you mean 'std::make_shared'? 
     std::shared_ptr<string> sp = make_shared<string>(str); // error... 
            ^~~~~~~~~~~ 
            std::make_shared 

Ich denke, die erste Funktion find nicht benötigt using Deklaration wegen argumentabhängiger Suche (ADL): der Compiler würde den Namespace suchen, in dem sich string befindet (dh std) für die Definition von find. Aber für die zweite Funktion make_shared scheint es, dass ADL nicht funktioniert: Ich muss stattdessen std::make_shared oder using Erklärung verwenden. Ich weiß, dass die Definitionen von zwei Funktionsschablonen unterschiedlich sind: der ehemalige nimmt einen seiner Schablonenparameter (typename T oder etwas Ähnliches) als Funktionsparametertyp und gibt den gleichen Typ zurück. Letzterer übernimmt das Funktionsparameterpaket als Funktionsparameter und sein Rückgabetyp ist ein weiterer Vorlagenparameter. Ist dieser Unterschied, der ADL deaktiviert? Oder könnten Sie die Frage beantworten und Referenzen geben?

+1

Die erste Verwendung ist spröde. Sie verlassen sich auf den unbestimmten Umstand, dass der Iteratortyp in 'std' lebt. Wenn an einem anderen Tag der Iteratortyp "const char *" ist, wird er nicht kompiliert. –

+0

Ich weiß, dass es eine brüchige Art ist, die 'using' Deklaration wegzulassen. Genau wie ein Vergleich mit dem zweiten> _ <|||. – chihyang

+0

@chihyang: Besseres Beispiel wäre 'begin (str)'. – Jarod42

Antwort

1

Argumentabhängige Lookup funktioniert für unqualifizierte Funktionsaufrufausdrücke. Dies gilt sowohl für "normale" Funktionen als auch für Funktionsvorlagenspezialisierungen.

Wenn Sie jedoch explizite Template-Parameter für eine Template-Funktion zur Verfügung stellen, dann wird der Ausdruck sieht nicht syntaktisch wie ein Funktionsaufruf:

foo<3>(x) // "foo less than three?" 

Das ist, warum diese Fälle nicht ADL auslösen. Sobald jedoch ein Name als Vorlage bekannt ist, gilt ADL!

template <int> void foo(); 

foo<double, 5, T>(x); // uses ADL 
+0

[Demo] (https://ideone.com/SKc0Sh) –

+0

Nun ... Ich habe den Weg in Ihrer Antwort versucht und es hat gut funktioniert! Aber es fühlt sich wirklich komisch an: Erklären Sie eine andere Funktionsvorlage, die wir nie verwenden werden, nur um dem Compiler mitzuteilen, dass der Name, den wir verwenden, eine Vorlage ist! Warum ist ADL so komisch? In C++ Primer benötigt es weniger als 3 Seiten. Aber jetzt scheint es eine große Falle zu sein! – chihyang

+0

@chihyang: Ja. Aber ich hoffe, dass Sie mit der Zeit feststellen werden, dass dies in realen Anwendungen normalerweise nicht so eine große Sache ist. –

0

Vorlagenmethoden verwenden nicht ADL, wenn wir explizit ihr Vorlagenargument mit <> angeben, außer wenn eine sichtbare Vorlagenmethode im Bereich vorhanden ist (mit demselben Namen).

+0

Nicht ganz. Zunächst gilt dies nur für Funktionsaufrufe mit explizit angegebenen Vorlagenparametern. Zweitens, wenn Sie auch eine andere Funktionsvorlage im Gültigkeitsbereich haben, gilt ADL. Die Einschränkung ist im Wesentlichen syntaktisch und nicht tiefgründig: Ohne eine existierende Deklaration sieht der Aufrufausdruck syntaktisch nicht wie ein Funktionsaufruf aus. –

+0

@KerrekSB: In der Tat. umformuliert. – Jarod42