6

Ich habe zwei Snippets für ADL zu Demozwecken. Beide Snippets wurden von VC10, gcc & Comeau C++ - Compiler kompiliert, und das Ergebnis ist das gleiche für alle drei.Warum hat ADL Vorrang vor einer Funktion in 'std namespace', ist aber in einem benutzerdefinierten Namespace gleich?

< 1> ADL gegen ein benutzerdefinierten Namespace-Richtlinie:

#include <algorithm> 
namespace N 
{ 
    struct T {}; 
    void swap(T,T) {} 
} 

namespace M 
{ 
    void swap(N::T,N::T) {} 
} 

int main() 
{ 
    using M::swap; 
    N::T o1,o2; 
    swap(o1,o2); 
} 

Compile Ergebnis:

error C2668: 'M::swap' : ambiguous call to overloaded function 
could be 'void M::swap(N::T,N::T)' 
or  'void N::swap(N::T,N::T)' [found using argument-dependent lookup] 

nimmt Dies wird erwartet, da ADL nicht Vorrang gegenüber normalen Ergebnis-Lookup plus ADL ist kein Bürger der 2. Klasse, das ADL-Suchergebnis ist mit normalem (nicht ADL-) unerlaubtem Lookup identisch. Deshalb haben wir die Zweideutigkeit.

< 2> ADL gegen std-Namespace-Richtlinie:

#include <algorithm> 
namespace N 
{ 
    struct T {}; 
    void swap(T,T) {} //point 1 
} 

namespace M 
{ 
    void swap(N::T,N::T) {} 
} 

int main() 
{ 
    using std::swap; 
    N::T o1,o2; 
    swap(o1,o2); 
} 

Dieses stellt ok.

Das Ergebnis ist Compiler wählen Sie ADL Ergebnis (es wird Präzedenzfall von Std :: Swap), dh N::swap() bei 'Punkt 1' wird aufgerufen. Nur wenn in der Abwesenheit von "Punkt 1" (sagen wir, wenn ich diese Zeile auskommentiere), wird die Kompilierung stattdessen den Fall std::swap verwenden.

Hinweis: Dieser Weg wurde an vielen Stellen verwendet, um die std::swap zu überschreiben. Aber meine Frage ist, warum hat ADL Vorrang vor 'std namespace' (case2) aber wird als benutzerdefiniert namespace Funktion (case1) gleich betrachtet?

Gibt es einen Absatz im C++ - Standard, der das sagt?

============================================== =============================== Bearbeiten nach dem Lesen nützlicher Antworten, könnte für andere hilfreich sein.

Also habe ich mein Snippet 1 & optimiert jetzt ist die Ambiguität verschwunden und kompilieren anscheinend Nontemplate-Funktion, wenn Überauflösung zu tun!

#include <algorithm> 
namespace N 
{ 
    struct T {}; 
    void swap(T,T) {} 
} 

namespace M 
{ 
    template<class T> 
    void swap(N::T,N::T) {} 
} 

int main() 
{ 
    using M::swap; 
    N::T o1,o2; 
    swap(o1,o2); //here compiler choose N::swap() 
} 

Ich habe auch mein Schnipsel 2 optimiert. Nur um die Mehrdeutigkeit nur zum Spaß erscheinen zu lassen!

#include <algorithm> 
namespace N 
{ 
    struct T {}; 

    template<class _Ty> inline 
    void swap(_Ty& _Left, _Ty& _Right) 
    { 
     _Ty _Tmp = _Move(_Left); 
     _Left = _Move(_Right); 
     _Right = _Move(_Tmp); 
    } 
} 

namespace M 
{ 
    void swap(N::T,N::T) {} 
} 

int main() 
{ 
    using std::swap; 
    N::T o1,o2; 
    swap(o1,o2); 
} 

gcc und comeau beide sagen Mehrdeutigkeit wie erwartet:

"std::swap" matches the argument list, the choices that match are: 
      function template "void N::swap(_Ty &, _Ty &)" 
      function template "void std::swap(_Tp &, _Tp &)" 

BTW VC10 dumm wie üblich lassen dies einem Durchgang in Ordnung, wenn ich die 'mit std :: Swap' entfernen.

Nur ein bisschen mehr zu schreiben: C++ Überlastung kann schwierig sein (30+ Seite in C++ Standard), aber bei appendlix B von dort eine gut lesbare 10-Seite gibt es ...

Danke für all die schönen Eingaben, jetzt ist es klar.

Antwort

9

Ihr Test überprüft nicht, ob ADL Vorrang vor der normalen Suche hat oder nicht, sondern wie die Überladungsauflösung die beste Übereinstimmung bestimmt. Der Grund dafür, dass der zweite Testfall funktioniert, ist, dass std::swap eine Vorlage ist, und wenn die Überladungsauflösung für eine perfekte Übereinstimmung (von ADL gefunden) und eine Vorlage ausgeführt wird, hat die nicht vorlagenbasierte Funktion Vorrang.

+0

Der beachtenswerte Punkt ist, dass ADL zu * name lookup * gehört, und Name lookup hat keine Vorstellung von "precedence". –

+0

@KerrekSB: Ich denke David sprach nach dem Namen Lookup-Phase, während in Überladung Auflösung, die alles über die Auswahl der besten Übereinstimmung ist. – Gob00st

12

Ein Funktionsaufruf geschieht in mehreren Stufen :

  1. -Namen-Suche -> stellt Funktionen Kandidaten in einer so genannten Überlastung gesetzt
    • dies der Teil ist, wo ADL passiert, wenn Sie haben einen unqualifizierten Namen Lookup
  2. Vorlage Argumentabzug -> für jede Vorlage in der Überlastsatz
  3. Überlastung Auflösung -> wählen Sie die beste Übereinstimmung

Sie sind Teil 1 mit Teil 3. Die Namenssuche verwirrend wird sowohl im Überlastsatz swap Funktionen tatsächlich setzen ({N::swap, std::swap}), aber Teil 3 wird darüber entscheiden, welche man am Ende anrufen.

Jetzt, da std::swap ist eine Vorlage, und der Standard sagt, dass Nicht-Template-Funktionen sind speziellere als Funktionen Vorlage, wenn eine Überlastung Auflösung zu tun, Ihre <2> Anrufe N::swap:

§13.3.3 [over.match.best] p1

Angesichts dieser Definitionen ist eine praktikable Funktion F1 als eine bessere Funktion definiert als eine andere funktionsfähige Funktion F2 wenn [...]

  • F1 ist eine Nicht-Template-Funktion und F2 ist eine Funktion Vorlage Spezialisierung [...]

† ich die ersten drei Videos von this excellent series zum Thema empfehlen.

+0

Also, kommentieren Sie bitte den Downvote? – Xeo

+0

Danke für die Standardreferenz! – Gob00st

+0

@Xeo: dunno (in Bezug auf den Downvote), der erste Satz verwirrte mich ein bisschen obwohl, weil der Compiler * alle * Funktionen, die möglicherweise aufgerufen werden nicht finden. Bei der Namenssuche geht es nur darum, eine Teilmenge zu finden. –

Verwandte Themen