Muss ich die Kommutativität für Vergleichsoperatoren manuell implementieren?

7

Mit n verschiedenen Klassen, die alle mit operator== und operator!= vergleichbar sein sollten, wäre es notwendig, (n ^ 2 - n) * 2 Operatoren manuell. (Zumindest denke ich, das ist der Begriff)

Das wäre 12 für drei Klassen, 24 für vier. Ich weiß, dass ich eine Menge von ihnen in Bezug auf andere Operatoren wie folgt umsetzen kann:

%Vor%

aber es scheint immer noch sehr langweilig, vor allem weil A == B immer das gleiche Ergebnis wie B == A ergibt und es scheint keinen Grund zu geben, zwei Versionen von ihnen zu implementieren.

Gibt es einen Weg dahin? Muss ich wirklich A == B und B == A manuell implementieren?

    
iFreilicht 12.06.2014, 18:45
quelle

4 Antworten

9

Benutze Boost.Operators , dann musst du nur eines implementieren und Boost definiert den Rest des Vortexes für Sie.

%Vor%

Dies erlaubt Instanzen von A und B für Gleichheit / Ungleichheit in beliebiger Reihenfolge zu vergleichen.

Live-Demo

Hinweis: private Vererbung funktioniert hier wegen des Barton-Nackman Trick .

    
Praetorian 12.06.2014 18:57
quelle
4

In den Kommentaren wird das Problem weiter erklärt, indem festgestellt wird, dass alle Typen wirklich verschiedene Formen von intelligenten Zeigern mit einem bestimmten zugrunde liegenden Typ sind. Das vereinfacht nun das Problem erheblich.

Sie können eine generische Vorlage für die Operation implementieren:

%Vor%

Nun, das ist ein böser Haken an der Implementierung (oder vielmehr an zu vielen). Sie können jedoch den Umfang des Operators eingrenzen, indem Sie ein Merkmal is_smart_ptr angeben, das erkennt, ob Ptr1 und Ptr2 einer Ihrer Smartpointer sind, und dann SFINAE verwenden, um Folgendes herauszufiltern:

%Vor%

Das Typmerkmal selbst kann nur eine Liste von Spezialisierungen einer Vorlage sein:

%Vor%

Es macht wahrscheinlich Sinn, nicht alle Typen aufzulisten, die mit dem Konzept des Zeigers übereinstimmen, sondern stattdessen nach dem Konzept zu suchen, wie:

%Vor%

Wo das getestete Konzept ist, dass operator* existiert. Sie können die SFINAE-Prüfung erweitern, um sicherzustellen, dass die gespeicherten Zeigertypen vergleichbar sind (d. H. Dass std::addressof(*lhs) und std::addressof(*rhs) eine gültige Gleichheit haben:

%Vor%

Und das ist wahrscheinlich so weit, wie Sie wirklich bekommen können: Sie können alles vergleichen, was wie ein Zeiger auf zwei möglicherweise nicht verwandte Objekte aussieht, wenn rohe Zeiger auf diese Typen vergleichbar sind. Möglicherweise müssen Sie den Fall aussortieren, in dem beide Argumente unformatierte Zeiger sind, um zu vermeiden, dass diese in eine rekursive Anforderung eingehen ...

    
quelle
3

nicht notwendig:

%Vor%

funktioniert für was auch immer A und B es gibt eine B == Eine Implementierung (andernfalls wird unendlich oft zurückgegriffen)

Sie können CRTP auch verwenden, wenn Sie nicht möchten, dass das templetized == für alles funktioniert:

%Vor%

Mit dem Rückgabetyp SFINAE können Sie sogar etwas wie

machen %Vor%     
Emilio Garavaglia 12.06.2014 18:59
quelle
2

Das Ziel hier ist, mit großen n einigermaßen effizient umzugehen.

Wir erstellen eine Reihenfolge und leiten alle Vergleichsoperatoren an comp weiter, nachdem wir sie neu angeordnet haben, um diese Reihenfolge zu befolgen.

Um dies zu tun, beginne ich mit einigen Metaprogrammierungsvorschlägen:

%Vor%

Hier können wir über geordnete Typenlisten sprechen. Als nächstes verwenden wir dies, um eine Reihenfolge für diese Typen festzulegen:

%Vor%

Jetzt machen wir ein paar Spielzeugtypen und eine Liste:

%Vor%

usw.

Die Grundidee ist, dass supp die Typen, die Sie unterstützen möchten, und ihre bevorzugte Reihenfolge auflistet.

Boilerplate-Operatoren leiten dann alles an comp weiter.

Sie müssen n * (n-1) / 2 comp s implementieren, um jedes Paar zu behandeln, aber nur in einer Reihenfolge.

Nun zu den schlechten Nachrichten: Wahrscheinlich möchtest du jeden Typ auf einen gewöhnlichen Typ heben und dort vergleichen, anstatt ihn im kombinatorischen Morast zu verlieren.

Angenommen, Sie können einen Typ Q definieren, der die Informationen speichern kann, die benötigt werden, um eine davon zu sortieren.

Dann schreiben Sie convert-to Q code von jedem Typ und implementieren Vergleich auf Q . Dies reduziert den in O (a + b) geschriebenen Code, wobei a die Anzahl der Typen und b die Anzahl der unterstützten Operatoren ist.

Als ein Beispiel können intelligente Zeiger auf diese Weise zwischeneinander angeordnet werden.

    
Yakk 13.06.2014 03:40
quelle