Methode und verschiedene Rückgabewerte
-
Hi,
ich habe folgende struct:
struct Data { bool bData; float fData; uint nData; };und einen enum:
enum DATA_TYPE { DATA_BOOL=0, DATA_FLOAT, DATA_UINT };Ich hätte jetzt gerne eine Funktion, die ein struct objekt und ein enum übergeben bekommt und mir den passenden Datenwert zurückgibt.
Geht das?Viele Grüße
Frank
-
Mach doch einfach 3 Funktionen.
float get_float ( Data const& data ); bool get_boolean ( Data const& data ); UINT get_uint ( Data const& data );Da kann man auch was mit templates machen, allerdings musst du dann innerhalb der Funktion die Auswahl des Typen machen.
-
Hier eine etwas andere Herangehensweise, die je nachdem, was du vor hast, möglicherweise besser passen könnte:
struct Data { bool bData; float fData; uint nData; }; enum DATA_TYPE { DATA_BOOL=0, DATA_FLOAT, DATA_UINT }; union return_Data{ bool bData; float fData; uint nData; }; return_Data foobar(Data input, DATA_TYPE chooser){ return_Data value; switch (chooser){ case DATA_BOOL: value.bData=input.bData; break; case DATA_FLOAT: value.fData=input.fData; break; case DATA_UINT: value.nData=input.nData; break; }; return value; } int main() { Data example={true,3.4, 7}; cout<< foobar(example,DATA_BOOL).bData <<" "<< foobar(example,DATA_FLOAT).fData << " "<< foobar(example,DATA_UINT).nData << endl; }Ich würde aber Einzelfunktionen oder Templates bevorzugen, wie von drakon vorgeschlagen.
-
Hmmmm, danke.
Das passt aber irgendwie alles nicht so ganz.
Eigentlich bräuchte ich eine einzige Funktion, die mir den richtigen konkreten Rückgabewert zurückgibt (also keine union, sonst muss ich ja nach Aufruf der Methode wissen, welcher Datentyp drin steht. Dann könnte ich auch gleich die struct auslesen.
Zur Laufzeit habe ich ein enum und einen struct. Ich brauche jetzt eine Funktion, die mir in Abhängikeit von diesen Beiden variablen den korrekten Datentypen zurückgibt? Geht das überhaupt? Wie würde eine Template Lösung aussehen?Vielen Dank euch Beiden!
Gruß
Frank
-
Nein. Das geht so nicht.
Eine Funktion hat lediglich einen Rückgabetypen, welcher zur Kompilierungszeit feststeht. Und nun kannst du da nicht einen anderen Typen zurückgeben. (mal abgesehen von Polymorphie und unterschiedlichen Laufzeittypen, aber das ist wahrscheinlich auch nicht das, was du willst).
Auch die template Variante läuft darauf hinaus, dass du zur Kompilierungszeit angeben musst, welche Funktion du aufrufen willst. (ob das explizit oder implizit über einen Parameter geschieht kommt ja auch auf das selbe hinaus).
Um eine elegante Lösung zu finden, solltest du eher mal das Problem beschreiben, welches du lösen möchtest, anstatt wie du es lösen möchtest.
-
Ok, das macht Sinn...
Um eine elegante Lösung zu finden, solltest du eher mal das Problem beschreiben, welches du lösen möchtest, anstatt wie du es lösen möchtest.
Ich versuchs mal:
Im Grunde hab ich 2 Klassen (A und B), die sich gegenseitig Daten schicken. Die Daten sind in einen Boost::Variant verpackt und können auf dem Weg zur anderen Klasse in einen anderen Datentypen umkonvertiert werden und/oder auf einen anderen Wert gemappt werden.
(Ich hatte in meinem ersten Beispiel oben einen struct benutzt, da ich nicht weiß, ob ein Boost::Variant so geläufig ist und imo in meiner Implementierung dasselbe bezweckt).
An den Beiden Enden (also in den Klassen selbst) gibt es eine receive Funktion, welche die Data in Form eines Boost::Variant und den zugehörigen Datentypen in Form eines enums bekommt.
Jetzt suche ich ganz einach nach einer Möglichkeit, ohne switch cases zu arbeiten, weil mein Code zur Zeit daran "erstickt". An allen Punkten, wo ich Konvertierungen/Mapping etc vornehme muss ich einen switch case einbauen um an den konkreten Wert zu kommen... vielleicht habe ich mit boost::variant auch nen Griff ins Klo gemacht
Viele Grüße
Frank
-
Hm. Hilft möglicherweise das Visitor-Pattern? Ich habe das mal* in Zusammenhang mit Boost.Variant gesehen, allerdings noch nie so verwendet. Ich denke, über Google und die Boost-Seite findest du dazu was.
_____
Das war im Buch "Beyond the C++ Standard Library: An Introduction to Boost".
-
Ja kenne ich, wird auch schon verwendet. Für das zu lösende Problem bringt es allerdings nichts, da man damit jeweils auch nur einen Datentypen zurückgeben kann.
Viele Grüße
Frank
-
Es kann natürlich sein, dass ich hier was falsch verstehe, da ich noch nie mit boost:variant gearbeitet habe, aber:
Ist das tolle an boost Variant denn nicht gerade, dass das Objekt quasi weiß, was es ist? Also, dass du einfach für das Empfangen ein Visitor pattern benutzen könntest:
class receiver : public boost::static_visitor<> { public: void operator()(bool & b) const { // Was mit bool geschehen soll } void operator()(float & f) const { // was mit float geschehen soll } void operator()(uint & n) const { // was mit uint geschehen soll } }; // ... boost::apply_visitor( receiver(), empfangene_daten );Also ganz ohne, dass man den Datentyp mitschickt?
-
Hi SeppJ,
das ist korrekt, allerdings müsste ich dann für jede Art der Konvertierung und Mappings eine eigene Visitor Klasse bauen. Komfortabel ist das auch nicht gerade...
Viele Grüße
Franklo