Ich versuche mit einem überladenen Operator == () ein Element in einem Vektor zu finden. Wenn Sie jedoch type1
im folgenden Code verwenden, lautet die Ausgabe 1 und 0 (nicht gefunden). Die Verwendung von type2
ergibt 1 und 1. Die Umgebung ist Xubuntu 12.04 und g ++ Version 4.6.3.
Die Antwort von @AlexanderGessler ist in einigen Details unvollständig. Lassen Sie uns den Compiler für beide Ausdrücke und beide Typen spielen, sollen wir?
cout << (v1 == v2) << endl;
Zunächst wird für type1
und type2
die Suche nach nicht qualifizierten Namen im Funktionsbereich main()
nach außen gestartet und findet im globalen Bereich Ihre eigene Funktion operator==
.
Zweitens findet die argumentabhängige Namenssuche (ADL) die Funktionsvorlage operator==
für std::pair
von namespace std
. Tatsächlich findet ADL viele weitere std::operator==
-Funktionsvorlagen (die aus std::vector
und std::string
, da Sie auch diese Header eingefügt haben).
Hinweis : ADL findet auch eine Übereinstimmung für type2
, weil die Basisklasse type1
namespace std
zur Menge der zugeordneten Namespaces hinzufügt.
3.4.2 Argumentabhängige Namenssuche [basic.lookup.argdep]
- Wenn T ein Klassentyp ist (einschließlich Vereinigungen), sind die zugehörigen Klassen: die Klasse selbst; die Klasse, der es angehört, falls vorhanden; und sein direkte und indirekte Basisklassen. Die zugehörigen Namespaces sind die Namespaces, deren zugehörige Klassen Mitglieder sind.
Drittens findet die Vorlagenargumentableitung für alle gefundenen Funktionsvorlagen statt. Für type1
wird nur die Funktionsvorlage für std::pair
die Argumentableitung überleben (und ihre Vorlagenargumente als std::string
bzw. int
ableiten). Für type2
gibt es jedoch keinen Satz von Template-Argumenten, die passen, weil type2
keine Instanziierung einer std::pair
-Template ist.
Viertens kommt die Überladungsauflösung ins Spiel. Für type1
haben sowohl Ihre eigene Funktion operator==
als auch die std::operator==
-Funktionsvorlage den gleichen Rang (Exact Match). Daher wählt der Tie-Break Ihre Nicht-Template-Funktion. Für type2
gibt es nur eine brauchbare Funktion, so dass die Überladungsauflösung nicht ins Spiel kommt und Ihre Funktion ausgewählt wird.
Fazit 1 : type1
und type2
geben die gleiche Antwort (Ihre Version ist ausgewählt), wenn auch aus verschiedenen Gründen.
cout << (find(vec.begin(), vec.end(), v2) != vec.end()) << endl;
Hier müssen wir zuerst den Aufruf von find
auflösen. Wegen Ihrer using namespace std;
findet die Suche nach nicht qualifizierten Namen bereits (kein Wortspiel beabsichtigt) std::find
, aber selbst ohne die using-Direktive hätte ADL auf dem std::vector
-Iterator es gefunden. Es leitet das dritte Template-Argument für std::find
entweder auf type1
oder type2
zurück.
Innerhalb von std::find
wurde ein Aufruf von operator==
gefunden. Wieder wird gewöhnliches Nachschlagen zuerst durchgeführt. Dies geschieht jedoch innerhalb von namespace std
. Es wird mehrere operator==
-Funktionsvorlagen finden (für std::vector
, std::string
und std::pair
). Sobald Kandidaten in einem Gültigkeitsbereich bei der Suche nach nicht qualifizierten Namen gefunden werden, endet diese Phase des Namens-Lookups.
ADL wird jedoch noch ausgeführt. Beachten Sie jedoch, dass der globale Namespace kein zugehöriger Namespace zu type1
ist, da es sich nur um einen typedef für eine Klasse in namespace std
handelt. Für type1
findet ADL also nichts Neues. Im Gegensatz dazu hat type2
den globalen Namespace als seinen zugeordneten Namespace und ADL wird in diesem Fall Ihre operator==
-Funktionsvorlage finden.
Für type1
findet Vorlage-Argumentabzug std::string
und int
als Vorlagenargumente für die Funktionsvorlage operator==
für std::pair
. Für type2
gibt es wiederum keinen Satz von Template-Argumenten, die passen, weil type2
keine Instanziierung einer std::pair
Vorlage ist.
Damit bleibt die Überladungsauflösung erhalten. Für type1
gibt es nur eine funktionsfähige Funktion (die Instanz der Vorlage std::operator==
), und die Überladungsauflösung kommt nicht ins Spiel. Für type2
gibt es auch nur eine lebensfähige Funktion (lebensfähig, da nur eine standardmäßige derived-to-base
-Konvertierung erforderlich ist). Daher kommt auch die Überladungsauflösung nicht ins Spiel.
Fazit 2 : Für type1
( std
version) und type2
(Ihre Version) erhalten Sie unterschiedliche Ergebnisse.
Nur weil diese Dinge mit mehreren Überladungen in verschiedenen Namespaces sehr knifflig werden können, hier ist eine Übersichtstabelle mit der heiligen Dreifaltigkeit (Namenssuche, Argumentabzug und Überladungsauflösung). Für jede Phase und für jeden Typ habe ich die überlebenden Kandidaten nach dieser Phase aufgelistet. Die untere Reihe zeigt die aufgerufene Funktion.
Ausdruck 1
%Vor%Ausdruck 2
%Vor% Beachten Sie, dass unqualifiziertes Suchen abhängig vom Startbereich (Funktionsumfang innerhalb des globalen Bereichs im Vergleich zum Namespacebereich) einen anderen Namen findet und dass ADL in Abhängigkeit davon, welcher Namespace als assoziiert betrachtet wird, ebenfalls einen anderen Namen findet ( namespace std
vs globaler Namespace).
std::pair
hat seinen Standardwert operator==
im Namespace std
. Dies ist eine Vorlage für beliebige Paare und vergleicht die Felder first
und second
. Dieser Operator wird in einem der vier Fälle ausgewählt, nämlich find
mit TYPE == type1
. Die Details sind jedoch ein wenig kompliziert:
Was tatsächlich für TYPE == type1
passiert ist (korrigiere mich wenn ich falsch liege)
v1 == v2
ADL ( Argumentabhängige Namenssuche ) wird angewendet, um operator==
in std
zu finden, was bedeutet, dass dieser Operator zur normalen Überladungsgruppe hinzugefügt wird. Allerdings wird die Nicht-Template-Version in der aktuellen Übersetzungseinheit immer noch gegenüber der Vorlage operator==
von std
. std::find
wird in std
instanziert, daher wird die Suche nach operator==
direkt in std
gestartet. Es findet eine Übereinstimmung (ohne Verwendung von ADL!) Und durchsucht daher nicht den umschließenden Bereich, der den eigenen Operator des OP enthalten hätte. Und für TYPE == type2
v1 == v2
ist einfach - es findet direkt den operator==
im umschließenden Namespace. std::find
wird auch in std
instanziert, aber der benutzerdefinierte Operator aus dem Hauptbereich wird zur Überladungsauflösung hinzugefügt, die mit ADL festgelegt wurde, und ist dann spezifischer als die in std
. std::pair
hat eine eigene operator==
, die Vorrang vor Ihrer eigenen hat.