Assoziatives C ++ - Array mit beliebigen Typen für Werte

7

Was ist der beste Weg, ein assoziatives Array mit beliebigen Werttypen für jeden Schlüssel in C ++ zu erstellen?

Gegenwärtig plane ich, eine "Wert" -Klasse mit Mitgliedsvariablen der Typen zu erstellen, die ich erwarten werde. Zum Beispiel:

%Vor%

Ein Nachteil dabei ist, dass Sie den Typ beim Zugriff auf den "Wert" kennen müssen. d.h.:

%Vor%

Je mehr Typen in Value eingefügt werden, desto aufgeblähter wird das Array.

Irgendwelche besseren Vorschläge?

    
Gerald Kaszuba 29.12.2008, 10:52
quelle

5 Antworten

14

boost :: variant scheint genau das zu sein, wonach Sie suchen.

    
Marc 29.12.2008, 11:02
quelle
9

Ihr Vorgehen war im Grunde in die richtige Richtung. Sie müssen den Typ kennen, in den Sie eingefügt werden. Sie können boost::any verwenden und Sie können so gut wie alles in die Karte einfügen, solange Sie wissen, in was Sie hineingelegt haben:

%Vor%

Einige Antworten empfahlen die Verwendung von boost::variant , um dieses Problem zu lösen. Aber Sie können keine willkürlichen typisierten Werte in der Karte speichern (wie Sie es wollten). Sie müssen die Menge der möglichen Typen vorher kennen. In Anbetracht dessen können Sie das obige leichter tun:

%Vor%

Das funktioniert, weil boost::variant überlädt operator<< für diesen Zweck. Es ist wichtig zu verstehen, dass Sie, wenn Sie das aktuell in der Variante enthaltene speichern möchten, den Typ immer noch wissen müssen, wie im Fall boost::any :

%Vor%

Die Reihenfolge der Zuweisungen zu einer Variante ist eine Laufzeiteigenschaft des Steuerungsflusses Ihres Codes, aber der Typ einer beliebigen Variablen wird zum Zeitpunkt der Kompilierung festgelegt. Wenn Sie also den Wert aus der Variante herausholen wollen, müssen Sie dessen Typ kennen. Eine Alternative ist die Verwendung von Visitationen, wie in der Variantendokumentation beschrieben. Es funktioniert, weil die Variante einen Code speichert, der angibt, welcher Typ ihm zuletzt zugewiesen wurde. Darauf basierend entscheidet zur Laufzeit welche Überladung der Besucher verwendet. boost::variant ist ziemlich groß und nicht vollständig standardkompatibel, während boost::any standardkonform ist, aber dynamischen Speicher auch für kleine Typen verwendet (daher ist es langsamer. Variante kann den Stapel für kleine Typen verwenden). Sie müssen also abwägen, was Sie verwenden.

Wenn Sie tatsächlich Objekte hineinlegen wollen, die sich nur dadurch unterscheiden, wie sie etwas tun, dann ist Polymorphie ein besserer Weg. Sie können eine Basisklasse haben, von der Sie abgeleitet sind:

%Vor%

Was würde dieses Klassenlayout grundsätzlich erfordern:

%Vor%

Der boost::shared_ptr ist ein so genannter Smart Pointer. Es löscht Ihre Objekte automatisch, wenn Sie sie aus Ihrer Karte entfernen und nichts mehr auf sie verweist. Theoretisch hätten Sie auch mit einem einfachen Zeiger arbeiten können, aber die Verwendung eines intelligenten Zeigers wird die Sicherheit erheblich erhöhen. Lies das Handbuch shared_ptr, mit dem ich verlinkt bin.

    
Johannes Schaub - litb 29.12.2008 10:58
quelle
2

Unterklasse Value mit IntValue , StringValue und so weiter.

    
Bombe 29.12.2008 10:56
quelle
2

Können Sie eine Union mit std :: map verwenden?

Boost :: variant bietet typlose Variablen.

Alternativ können Sie alle Datenelemente für "Wert" als privat festlegen und Zugriffsberechtigungen bereitstellen, die einen Fehler (oder "throw") zurückgeben, wenn dieser Wert nicht festgelegt ist.

    
Patrick 29.12.2008 11:00
quelle
1

Eine direkte Optimierung wäre die Verwendung von union , da Sie immer nur einen der Werte als Schlüssel haben.

Eine vollständigere Lösung würde einige Laufzeittypinformationen in eine Schnittstelle einkapseln. In erster Linie "Welcher Typ ist das?" und "Wie vergleiche ich Werte für Gleichheit?" Verwenden Sie dann Implementierungen von diesem als Schlüssel.

    
David Schmitt 29.12.2008 11:01
quelle

Tags und Links