Map von Unions verwalten
-
Decimad schrieb:
Vielleicht kann ja jemand aushelfen
Dass STL-Container nicht zur Vererbung konzipiert sind, sollte eigentlich schon reichen.
Ansonsten könnte man sagen, dass man zusätzliche Funktionalität ebenso gut als freie Funktionen implementieren kann. Das hat den Vorteil, dass man keine neuen Container-Klassen definieren muss, und auch andere Programmieren die Anwendung verstehen (hingegen müssen sie
MyMaperst mal kennen).
-
Decimad schrieb:
Gehen wir nun davon aus, das ginge, woher weiß der Client den Typ der einzelnen Elemente?
Naja, der Nutzer könnte halt vorher per Hilfsfunktion erfragen, welche Typ in der Map gespeichert wird. Der Compiler weiß dies natürlich nicht. Die Frage ist deshalb, ob ich das grundsätzlich irgendwie realiseren kann. Per void-Pointer vielleicht, auch wenn das unschön ist.
Dass STL-Container nicht zur Vererbung konzipiert sind, sollte eigentlich schon reichen.
Ok, also eher den Container als Member halten?
-
Michamab schrieb:
Ok, also eher den Container als Member halten?
Ja, oder eben freie Funktionen einrichten, wenn du keine zusätzlichen Daten in der Klasse brauchst.
Value& at(std::map<int, Value>& map, int key); const Value& at(const std::map<int, Value>& map, int key);
-
Was hast du denn mit dieser Map vor, die 2 Datentypen innehat?
Sag uns das mal, vielleicht gibt es da andere Möglichkeiten.
-
Naja, ich habe eine Schnittstelle, die eine assoziative Liste von Werten entgegen nimmt. Die Schlüssel sind immer gleich, aber die dazugehörigen Werte sind halt mal Floats und mal Integers. Da die Liste recht groß sein kann, will ich die Map halt nicht ständig kopieren, sondern nur den Wertebereich ändern. Deshalb dachte ich erst an eine Map von Unions, so dass ich nur einmal Speicher allokieren muss.
-
Das heißt, du möchtest an jeglicher Stelle, an der die Attribute benötigt werden, überprüfen und je nachdem ob heute mal Integer angesagt ist oder Float eigene Codepfade haben?
Ich kann gerade einfach nicht nachvollziehen wie sich der Wertetyp von ein- und derselben Eigenschaft ändert.
Und zum anderen können sich auch floating-point werte u.U. dafür eignen, die integer-werte zu speichern.
-
Ja, es geht ja jetzt hier nicht nur um Float und Integer, sondern eventuell auch um Double etc. Und ja, hinter der Schnittstelle stecken dann verschiedene Codepfade für die verschiedenen Wertebereiche. Die Liste ist halt eventuell ziemlich lang und deshalb soll sie nicht komplett "neu gebaut" werden.
-
Also in etwa so:
void mein_algo() { typ = fiktiv.get_typ("bla"); switch( typ ){ case TYP1: break; case TYP2: break; case TYP3: break; case TYP4: break; case TYP5: break; case TYP6: break; default: throw std::runtime_error( "Fuer diesen Typ wurde leider der Algorithmus \"mein_algo\" noch nicht erweitert" ); } }oder etwas ähnliches?
-
Ja so in der Art soll das laufen:
void tueWas(int typ, MyMap &map) { switch(typ) { case 0: ... break; // hier brauche ich Integer-Werte in der Map case 1: ... break; // hier brauche ich Float-Werte in der Map case 2: ... break; // hier brauche ich wieder Integer-Werte default: ... } }So soll das ungefährt von Nutzerseite laufen
MyMap verdammtGrosseMap(); // Speichert per default Integer verdammtGrosseMap[KEY_1] = 3; ... verdammtGrosseMap[KEY_X] = 8; tueWas(MODE1, verdammtGrosseMap); verdammtGrosseMap.speichereJetztFloat(); verdammtGrosseMap[KEY_1] = 3.5; ... verdammtGrosseMap[KEY_X] = 10.4 tueWas(MODE2, verdammtGrosseMap) ...Ich will halt irgendwie vermeiden, dass ich die Map ständige neu konstruieren muss. Für Anregungen bin ich dankbar.
-
Also bei n möglichen Typen musst du jeden einzelnen der m Algorithmen n-mal implementieren. Das kann es doch nicht sein, was du willst?
Würde es vielleicht helfen, einfach alle Variablen als double abzuspeichern? Dann hast du auch Integer bis +-2^53-1 totgeschlagen.
-
Also werden in der Map zu einem Zeitpunkt immer die gleichen Wert-Typen gespeichert?
Jetzt steige ich noch weniger durch. Aber vielleicht willst du die Funktion einfach nur über den Werte-Typ der Map templatisieren?Edit: nee, das ist es auch nicht. Kannst du einen einfachen realistischen Use-Case aufzeigen, bei dem man mal sieht, wozu das Typ-Rumgeschiebe dienen soll?
-
Int ist das neue Float schrieb:
Also in etwa so:
void mein_algo() { typ = fiktiv.get_typ("bla"); switch( typ ){ case TYP1: break; case TYP2: break; case TYP3: break; case TYP4: break; case TYP5: break; case TYP6: break; default: throw std::runtime_error( "Fuer diesen Typ wurde leider der Algorithmus \"mein_algo\" noch nicht erweitert" ); } }oder etwas ähnliches?
Und genau sowas widerspricht jeglichen Paradigmen oder Code Standards.
- Du hast Redundanzen an sehr vielen Stellen
- Ok, Magic Numbers hast du nicht direkt, aber das hast du in Konstanten ausgelagert
- du betreibst meiner Meinung nach Premature Optimizing. Zum einen sollte es auf dem Level egal sein, ob int's oder floats/doubles gespeichert werden. Und zum anderen, falls du trifftige Gründe hast, dass du die absolute Genauigkeit von int brauchst, dann solltest du es auch nutzen. Aber da wird es sicherlich eine bessere Möglichkeit geben als Datentypen in einer Map zu mixen.Was hast Sone so schön in seinem Anhängsel stehen:
Sone schrieb:
Du möchtest Problem X mit Möglichkeit Y lösen. Aber anstatt nach X zu fragen, fragst und beharrst du auf Y.
-
Decimad schrieb:
Also werden in der Map zu einem Zeitpunkt immer die gleichen Wert-Typen gespeichert?
Jetzt steige ich noch weniger durch. Aber vielleicht willst du die Funktion einfach nur über den Werte-Typ der Map templatisieren?Edit: nee, das ist es auch nicht. Kannst du einen einfachen realistischen Use-Case aufzeigen, bei dem man mal sieht, wozu das Typ-Rumgeschiebe dienen soll?
Also bei n möglichen Typen musst du jeden einzelnen der m Algorithmen n-mal implementieren. Das kann es doch nicht sein, was du willst?
Würde es vielleicht helfen, einfach alle Variablen als double abzuspeichern? Dann hast du auch Integer bis +-2^53-1 totgeschlagen.Genau, meine ursprüngliche Idee war, dass in der Map zu einem Zeitpunkt immer nur Werte eines Typs gespeichert sind, weil der Typenwechsel eher selten stattfindet. Dieser Punkt ist mir allerdings nicht so wichtig. Ich könnte mir auch vorstellen, dass Werte verschiedener Typen zum selben Zeitpunkt einem Key zugeordnet sind, also eine Art Tabelle. Wichtig ist mir halt, dass die Struktur möglicht speichereffizient ist.
Bzgl. der Anwendung ist zu sagen, dass keine redundanten Algorithmen für die jeweiligen Typen implementiert sind. Unter dem Interface sind einige Protokolle implementiert, die verschiedene Datentypen für verschiedene Eigenschaften entgegennehmen. Der Key in der Map definiert eine Empfänger-Instanz. Die Map wird dann durchiteriert und der jeweilige Wert an alle Empfänger bildlich gesprochen "verschickt". Das dort halt mal double-Werte und mal Integer-Werte genutzt werden, entzieht sich meinem Einfluss.
Nun ist halt der Punkt, dass ich in der Regel immer nur die selbe Menge von Empfängern sehr häufig hintereinander anspreche. Z.B. will ich eine Eigenschaft manipulieren, die ein Integer-Werte entgegennimmt. Dann könnte es passieren, dass ich eine Eigenschaft manipuliere, welche einen Double-Wert entgegennimmt. Wie oben schon erwähnt, will ich meine Liste von Empfängern nicht neu instanziieren, sondern nur einen anderen Wertebereich nutzen.
Mag durchaus sein, dass meine Herangehensweise ein Irrweg ist. Aber einfach alle Daten im größtmöglichen Datentyp zu speichern ist leider keine Option, weil nicht klar ist, ob dieser Datentyp überhaupt benötigt wird und der zusätzliche Speicherverbrauch vermieden werden soll.
Ich hoffe klingt jetzt nicht alzu verwirrend. Ich bin über jede Anregung dankbar.
-
Hrmmm, du möchtes also eigentlich heterogene Nachrichten an durch Strings idetinfizierbare Empfänger schicken?
-
Decimad schrieb:
Hrmmm, du möchtes also eigentlich heterogene Nachrichten an durch Strings idetinfizierbare Empfänger schicken?
Genau, allerdings entzieht sich das Interface, über das ich die Nachrichten verschicke, meinem Einfluss. Manchmal werden dort halt Gleitkommazahlen erwartet, manchmal Integer-Werte, je nachdem welche Eigenschaft manipuliert wird. Da ich aber häufig den Fall habe, dass die für die selbe Menge von Empfängern mehrere Eigenschaften manipulieren will, brauch ich eine Datenstruktur, die dies handhabbar macht. Sprich, die X Keys mal auf Integer-Werte, mal auf Double-Werte, abbildet, ohne diese Map jeweils neu zu instanziieren.
-
Wer bestimmt denn dann das Interface? Irgendjemand muss sich doch miteinander unterhalten und die sollten doch auch die gleiche Sprache sprechen.
-
Naja, das ist halt eine API, mit der ich mich unterhalte. Auf diese habe ich wie gesagt keinen Einfluss. Nun will ich sie clever kapseln, und dafür benötige ich eben die benannte Lösung.
-
Du musst verzeihen, wenn ich da halt so rumstochere, aber mir kommt schon alleine die Idee, Nachrichten in einer Map vorzuhalten, dann auch noch von unterschiedlichem Typ, irgendwie komisch vor. Wie sieht denn die API grob aus? Wenn du keine Lust hast, einfach die API zu benennen, könntest du ja ein paar Prototypen zeigen mit etwas generischer Semantik, dass man sich da einmal einen Reim drauf machen kann.
-
Naja, ich habe das ganze schon etwas vereinfacht, deshalb will ich hier nicht die Details ausrollen. Aber im Grunde sieht das Ganze so aus:
typedef enum { A, B, C, ... } Empfaenger; sendFoo(Empfaenger empfaenger, double d); sendBar(Empfaenger empfaenger, int i);
-
Okay, und warum musst Du nun die Nachrichten zwischenspeichern, statt sie direkt zu versenden?