Ich habe den folgenden vereinfachten Code
%Vor%Und ich habe diesen Fehler:
%Vor%error: kann die Elementfunktion 'int Namespace :: Class :: foo () const' nicht aufrufen ohne Objekt:
Es scheint, dass der Compiler die nicht statische int Namespace::Class::foo() const
anstelle der globalen Funktion int Namespace::foo()
auswählt.
Aber wie kann man erwarten, dass nicht-statische Funktion von einer anderen Klasse ohne Objekt aufgerufen werden kann? Nested object
hat keinen Zugriff auf den umgebenden Class object
- das ist doch nicht Java.
Ich lese sorgfältig Überladungsauflösung von cppreference Ich kann die Gründe für dieses Verhalten nicht finden. Ich bezweifle, dass dies ein GCC-Fehler ist.
Nur eine Antwort für die zweite Frage. Umgehung ist einfach, es ist notwendig, dem Compiler mitzuteilen, dass eine solche globale Funktion existiert:
%Vor%Übrigens, ist diese Problemumgehung korrekt? Gibt es bessere Lösungen?
Ich habe die Überladungsauflösung von cppreference sorgfältig gelesen. Ich kann die Gründe für dieses Verhalten nicht finden. Können Sie auf die für dieses Verhalten verantwortlichen Sprachregeln verweisen?
Bevor die Prozedur Überladungsauflösung die beste funktionsfähige Funktion auswählt, wird während der -Namensuche -Phase eine erste Menge von Kandidaten generiert. Mit anderen Worten, das erwartete Verhalten sollte im Abschnitt Name-Suche gesucht werden, nicht im Überladungsauflösung .
Die Namenssuchprozedur für einen nicht qualifizierten Namen wird im C ++ - Standard beschrieben:
§3.4.1 [basic.lookup.unqual] / p8:
Ein Name, der in der Definition einer Elementfunktion (9.3) der Klasse
X
nach der deklarator-ID der Funktion oder in der geschweiften Klammer oder verwendet wird -equal-initializer eines nicht statischen Datenmembers (9.2) der KlasseX
muss auf eine der folgenden Arten deklariert werden:- vor seiner Verwendung in dem Block, in dem es verwendet wird oder in einem umschließenden Block (6.3) oder
- soll ein Mitglied der Klasse X sein oder ein Mitglied einer Basisklasse von X (10.2) oder
sein- wenn
X
eine verschachtelte Klasse der KlasseY
(9.7) ist, ein Mitglied vonY
sein oder Mitglied einer Basisklasse vonY
sein soll (Diese Suche bezieht sich wiederum auf umschließende Klassen vonY
, beginnend mit der innersten umschließenden Klasse) oder [...]
und nur wenn noch nicht gefunden:
- Wenn
X
ein Mitglied des NamespaceN
ist oder eine geschachtelte Klasse einer Klasse ist, die Mitglied vonN
ist oder eine lokale Klasse oder eine geschachtelte Klasse ist innerhalb einer lokalen Klasse einer Funktion, die ein Mitglied vonN
ist, vor der Verwendung des Namens im NamespaceN
oder in einem vonN
's umschließenden Namespaces.
Da die Namenssuche endet, sobald der Name gefunden wurde (§3.4.1 [basic.lookup.unqual] / p1):
In allen Fällen, die in 3.4.1 aufgelistet sind, werden die Bereiche nach einer Deklaration in der Reihenfolge gesucht, die in jeder der jeweiligen Kategorien aufgeführt ist; Die Namenssuche endet, sobald eine Deklaration für den Namen gefunden wird.
in Ihrem Fall werden keine anderen Bereiche gesucht, sobald int foo() const { return 2; }
gefunden wurde.
Problemumgehung ist einfach, es ist notwendig, dem Compiler mitzuteilen, dass eine solche globale Funktion existiert:
%Vor%Ist diese Problemumgehung korrekt?
§7.3.3 [namespace.udecl] / p1:
Eine using-Deklaration führt einen Namen in die deklarative Region ein, in der die using-Deklaration erscheint.
§3.3.1 [basic.scope.declarative] / p1:
Jeder Name wird in einen Teil des Programmtexts eingeführt, der als deklarative Region bezeichnet wird. Dies ist der größte Teil des Programms, in dem dieser Name gültig ist. in dem dieser Name als ein unqualifizierter Name verwendet werden kann, um auf dieselbe Entität zu verweisen.
Die Einführung eines Namens mit einer using-Deklaration wirkt sich auf die unqualifizierte Namenssuche so aus, dass sie diese Funktion in ihrem ersten Schritt findet, nämlich dass dieser Name zu deklariert :
- vor seiner Verwendung in dem Block, in dem es verwendet wird oder in einem umschließenden Block (6.3)
Gibt es bessere Lösungen?
Man kann einen qualifizierten Namen verwenden, wenn er sich auf eine Funktion aus einem Namespace-Bereich bezieht und explizit angibt, auf welches Symbol verwiesen wird:
%Vor%In der Tat ging es um die Namenssuche und nicht um die Überladungsauflösung.
Wie der Standard festlegt, §3.4.1 / 1 von N3376 (Hervorhebung von mir):
In allen Fällen, die in 3.4.1 aufgelistet sind, werden die Bereiche nach einer Deklaration in der Reihenfolge gesucht, die in jeder der jeweiligen Kategorien aufgeführt ist; Die -Namensuche endet, sobald eine Deklaration für den Namen gefunden wird. Wenn keine Deklaration gefunden wird, ist das Programm schlecht formatiert.
In der Tat stoppt die Suche, sobald eine Deklaration gefunden wird.
Dann können Sie mehr über den Fall, mit dem Sie es zu tun haben, in §3.4.1 / 8 finden, der sich mit Namen beschäftigt, die in der Klasse innerhalb einer Memberfunktionsdefinition verwendet werden, insbesondere diesen Teil:
wenn X eine geschachtelte Klasse der Klasse Y (9.7) ist, ein Mitglied von Y oder ein Mitglied einer Basisklasse von Y sein soll (diese Suche gilt wiederum für die einschließenden Klassen von Y, beginnend mit dem innersten Einschluss) Klasse)
Und falls nicht gefunden, in umschließenden Namespaces.
In Ihrem Fall bedeutet das, dass Namespace::Class::foo()
der erste Name ist, der während der Suche gefunden wurde, und er stoppt, sobald er einen Namen gefunden hat, also wird Namespace::foo()
nicht einmal berücksichtigt.
Das Beispiel des Standards veranschaulicht den Suchpfad:
%Vor%Die folgenden Bereiche werden nach einer Deklaration von i durchsucht:
1) äußerster Blockbereich von M :: N :: X :: f, vor der Verwendung von i // 2) Bereich der Klasse M :: N :: X
3) Umfang der Basisklasse B von M :: N :: X
4) Geltungsbereich des Namensraums M :: N
5) Geltungsbereich des Namensraums M
6) globaler Gültigkeitsbereich vor der Definition von M :: N :: X :: f
Und wie Sie mit einem solchen Problem umgehen, müssen Sie den Anruf qualifizieren, d. h.
%Vor%, damit der Compiler die gewünschte Funktion durch qualifizierte Suche auswählt.
Piotr S. und JBL haben das Warum Ihres Problems erklärt.
IMHO die einfachere Lösung ist, den qualifizierten Namen der Funktion zu verwenden:
%Vor%Tags und Links c++ gcc argument-dependent-lookup