Related: Was kann ich als std::map
keys verwenden?
Ich musste ein Mapping erstellen, bei dem bestimmte Schlüsselpositionen im Raum Listen von Objekten zugeordnet werden. std::map
schien der richtige Weg dafür zu sein.
Also gebe ich ein std::map
auf einem xyz Vector
, und ich mache eine std::map<Vector, std::vector<Object*> >
. Also notiere den Schlüssel hier ist nicht a std::vector
, es ist ein Objekt von class Vector
, das ist nur ein mathematischer xyz Vektor, den ich selbst mache.
Um eine "strikt schwache Reihenfolge" zu erzeugen, habe ich die folgende Überladung für operator<
:
Es ist ein bisschen lang, aber es macht grundsätzlich so, dass jeder Vektor konsistent als kleiner als jeder andere Vektor ((-1, -1, -1) & lt; (-1, -1,1) und ( -1, -1, 1) & gt; (-1, -1, -1) zum Beispiel).
Mein Problem ist, dass es wirklich künstlich ist und obwohl ich es programmiert habe und es funktioniert, finde ich heraus, dass es meine Vector-Klasse (mathematisch) mit dieser wirklich seltsamen, künstlichen, nicht auf Mathematik basierenden Vorstellung "verschmutzt". weniger als "für einen Vektor.
Aber ich muss ein Mapping erstellen, wo bestimmte Schlüsselpositionen im Raum auf bestimmte Objekte abgebildet werden, und std :: map scheint der Weg dafür zu sein.
Vorschläge? Out-of-Box-Lösungen sind willkommen!
Anstatt operator<
für Ihre Schlüsselklasse zu definieren, können Sie der Karte einen benutzerdefinierten Vergleicher zuweisen. Dies ist ein Funktionsobjekt, das zwei Argumente akzeptiert und true
zurückgibt, wenn das erste vor dem zweiten steht. Etwas wie das:
Sie können es von der Klasse trennen. Dann spezifizieren Sie es als Vergleichsoperator für die std :: map.
%Vor% Where Compare ist eine Funktion (oder ein Funktor), die Vektorobjekte miteinander vergleichen kann.
Ich denke auch, dass Sie Ihre Vergleichsoperation vereinfachen können.
Beachten Sie, dass wir weniger als größer testen und dann gleich durchfallen. Persönlich mag ich die Einfachheit dieses Stils. Aber ich sehe oft, dass das so komprimiert ist:
%Vor% Ich denke std::tr1::unordered_map
ist genau das, was Sie brauchen. Es ist keine strenge schwache Reihenfolge erforderlich. GCC hat etwas ähnliches in tr1
namespace. Oder gehen Sie zu Boost.Unordered .
Die ungeordneten Gegenstücke des mehr Fußgänger map
oder set
gibt Ihnen zwei Vorteile:
Sie müssen keinen less-than-Operator definieren, wenn keiner Sinn ergibt
Hashtabellen können bessere Ergebnisse erzielen als ausgeglichene Binärbäume, wobei letzterer die bevorzugte Methode zur Implementierung der bestellten map
- oder set
-Strukturen ist. Dies hängt jedoch von Ihren Datenzugriffsmustern / Anforderungen ab.
Also, mach einfach weiter und benutze:
%Vor%Dies verwendet eine Standard-Hash-Funktion, die sich um das Einfügen / Suchen Ihrer Map kümmert.
PS: Das > >
dingy wird in den kommenden Standard und damit zukünftigen Compiler-Versionen behoben werden.
Es ist normal, dass Sie feststellen, dass Ihre Klasse dadurch verunreinigt ist. Es ist auch aus Sicht der CS verschmutzt.
Der normale Weg, einen solchen Operator zu definieren, ist durch (möglicherweise Freund) freie Funktionen.
Die erste Frage, die Sie sich stellen sollten, ist: macht es Sinn? Das Problem ist, dass Sie eine Methode für Ihre Klasse definiert haben, die nur in einem begrenzten Kontext sinnvoll ist, aber überall zugänglich ist. Deshalb tritt das "Verschmutzungsgefühl" auf.
Wenn ich nun ein solches Mapping von einem Vector
zu einer Sammlung von Object
s benötigen würde, sind hier die Fragen, die ich mir stellen möchte:
Vector
bestellen? Ja: std::map
, Nein: std::unordered_map
oder std::tr1::unodered_map
oder std::hash_map
oder boost::unordered_map
. Object
? Ja: boost::ptr_vector<Object>
oder std::vector< std::unique_ptr<Object> >
, Nein: std::vector<Object*>
Nun, in beiden Fällen ( map
und unordered_map
) brauche ich etwas, um meinen Schlüssel zu transformieren. Die Sammlung bietet ein zusätzliches Template-Argument, das einen Funktor-Typ annimmt.
Vorsicht: Wie in einer anderen Antwort erwähnt, ist die Gleitkommadarstellung in einem Computer schwierig, daher müssen Sie wahrscheinlich die Bedeutung von Gleichheit lockern und die Zahlen niedrigerer Ordnung ignorieren (wie viele davon von Ihren Berechnungen abhängen).
Ich denke, Ihre Vorgehensweise ist in Ordnung. Wenn Sie sich Sorgen machen, die Vector-Klasse zu verschmutzen, dann glaube ich, dass eine eigenständige Funktion genauso gut funktioniert:
%Vor%Aber nur ein Wort der Warnung: Was Sie hier tun, ist ziemlich riskant. Bei Gleitkommaberechnungen treten häufig Fehler auf. Angenommen, Sie fügen einen Punkt in Ihre Karte ein. Dann berechnen Sie einen Punkt und überprüfen Sie die Karte, um zu sehen, ob es da ist. Auch wenn der zweite Punkt aus streng mathematischer Sicht derselbe ist wie der erste, gibt es keine Garantie, dass Sie ihn in der Karte finden.
Tags und Links math c++ operator-overloading stdmap