find () mit überladenem Operator ==

8

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.

%Vor%     
user2847598 04.10.2013, 17:57
quelle

4 Antworten

4

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?

Ausdruck 1

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.

Ausdruck 2

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.

Zusammenfassung

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).

    
TemplateRex 04.10.2013, 22:45
quelle
8

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)

  • für 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 .
  • bevorzugt
  • Der Aufruf von 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 .
Alexander Gessler 04.10.2013 18:00
quelle
1

std::pair hat eine eigene operator== , die Vorrang vor Ihrer eigenen hat.

    
Mark Ransom 04.10.2013 18:01
quelle
1

Ich denke, dass es besser ist, find_if zu verwenden anstatt zu finden. Es braucht ein Prädikat, so dass Sie Ihren Vergleicher einfach als normale Funktion / Funktor definieren und übergeben können.

    
shash 04.10.2013 18:09
quelle