In Bezug auf die Definition von Freundesfunktionen und Namespace-Bereiche

8

Ich habe diesen Blogbeitrag gelesen und versucht, herumzuspielen mit dem Snippet, das bereitgestellt wurde.

%Vor%

Wenn ich richtig verstanden habe, wird die Definition in // 1 den Namen f einfügen, wo sich // 2 befindet. Es wird jedoch nur über eine argumentabhängige Suche verfügbar sein. Gut.

Es gibt einen Satz in der Post, der meine Aufmerksamkeit erregt hat:

  
    
      

7.3.1.2/3 Namensraum-Elementdefinitionen [namespace.memdef] p3

    
         

Jeder Name, der zuerst in einem Namespace deklariert wird, ist ein Mitglied dieses Namespace. Wenn eine Friend-Deklaration in einer nicht-lokalen Klasse zuerst eine Klasse, Funktion, Klassenvorlage oder Funktionsvorlage deklariert, ist der Freund ein Mitglied des innersten umschließenden Namespace. Die Friend-Deklaration macht den Namen nicht für unqualifiziertes Nachschlagen (3.4.1) oder qualifiziertes Nachschlagen (3.4.3) sichtbar.

  
     

Beachten Sie, dass nirgends angegeben wird, dass der Name, der von einer Freund-Deklaration eingeführt wird, irgendeine besondere Beziehung zum Namen der Klasse haben muss, in der er deklariert und / oder definiert wird, oder zu einer bestimmten Beziehung zu der Klasse überhaupt ).

Davon dachte ich, das folgende Snippet wäre gültig gewesen:

%Vor%

Aber es wird von GCC7 und Clang 4 abgelehnt.

  

t.cpp: 19: 3: Fehler: 'f' wurde in diesem Bereich nicht deklariert

Das lustige ist, dass wenn ich versuche, f mit einem N::B -Objekt aufzurufen, bekomme ich den folgenden Fehler:

  

t.cpp: 12: 6: Fehler: konnte 'b' nicht von 'N :: B' zu 'N :: A'

konvertieren

Also hier ist meine Frage:

Sollte nicht f(A) über ADL erkannt werden? Da beide Klassen im Namensraum sind, sehe ich nicht, warum dies fehlschlägt. Ich habe im Standard den Abschnitt über Freunde gelesen, aber keinen relevanten Abschnitt gefunden.

Ich frage mich, in welchem ​​Umfang f(A) injiziert wurde, da GCC es finden kann, wenn ich versuche, über den Aufruf von f(B) den falschen Argumenttyp anzugeben.

    
Dante 06.09.2017, 11:15
quelle

1 Antwort

2

Von cppreference/cpp/language/friend :

  

Ein zuerst in einer Friend-Deklaration in der Klassen- oder Klassenvorlage deklarierter Name X wird Mitglied des innersten einschließenden Namespace von X , ist aber nicht für die Suche verfügbar (außer für die argumentabhängige Suche, die X berücksichtigt) es sei denn, eine übereinstimmende Deklaration im Namespace-Bereich wird bereitgestellt. Weitere Informationen finden Sie unter Namespaces .

Von cppreference/cpp/language/namespace :

  

Namen, die von Friend-Deklarationen innerhalb einer nicht-lokalen Klasse X eingeführt werden, werden Mitglieder des innersten einschließenden Namespace von X , aber sie werden nicht sichtbar (weder unqualifiziert noch qualifiziert), es sei denn, es wird eine übereinstimmende Deklaration bereitgestellt Namensraumbereich entweder vor oder nach der Klassendefinition. Ein solcher Name kann über ADL gefunden werden, der sowohl Namespaces als auch Klassen berücksichtigt.

Dies stimmt mit Ihrem Beispiel überein - f benötigt eine A , die nicht dem Typ der einschließenden Klasse entspricht.

Wenn Sie Ihr Beispiel in ... ändern

%Vor%

... es wird kompiliert.

Verwandte Standardzitat:

  

$ 14.3 [klasse.friend]

     
    

Ein Freund einer Klasse ist eine Funktion oder Klasse, der die Berechtigung erteilt wurde, die privaten und geschützten Mitgliedsnamen aus der Klasse zu verwenden. [...] Eine Funktion kann in einer Friend-Deklaration einer Klasse genau dann definiert werden, wenn die Klasse eine nicht-lokale Klasse ([class.local]) ist, der Funktionsname nicht qualifiziert ist und die Funktion einen Namensraumbereich hat. [...] Eine solche Funktion ist implizit eine Inline-Funktion. Eine in einer Klasse definierte Friend-Funktion befindet sich im (lexikalischen) Bereich der Klasse, in der sie definiert ist. Eine außerhalb der Klasse definierte Friend-Funktion ist nicht ([basic.lookup.unqual]).

  
    
Vittorio Romeo 06.09.2017, 12:26
quelle