2 verschiedene Rückgabetypen per Template



  • hustbaer schrieb:

    D.h. du willst Playlisten aus Tracks und weiteren "Unterplaylisten" zusammensetzen können?
    Also wie Verzeichnisse Files und weitere Unterverzeichnisse enthalten können?

    Nein, Unterplaylisten existieren nicht.

    Wenn ich euch richtig verstanden habe, dann meint ihr einfach Playlist als Base-Klasse für Track zu verwenden?



  • eher:

    #include <vector>
    
    struct playable { void something() {} };
    class track : public playable {};
    class playlist : public playable { std::vector< track > tracks; };
    
    void bar( playable &thing ) { thing.something(); }
    
    int main()
    {
    	std::vector< playlist > playlists( 3 );
    	track foo;
    
    	playlists[ 0 ].something();
    	foo.something();
    
    	bar( playlists[ 0 ] );
    	bar( foo );
    }
    

    ?



  • heyo schrieb:

    Wenn ich euch richtig verstanden habe, dann meint ihr einfach Playlist als Base-Klasse für Track zu verwenden?

    NEIN!
    Wie kann man das was SeppJ geschrieben hat nur so falsch verstehen? *facepalm*

    Du sollst eine Klasse machen wo du reinpackst was gemeinsam ist, und dann sowohl Playlist als auch Track von dieser gemeinsamen Basisklasse ableiten.



  • @hustbare & @Swordfish
    So hab ich es ja bereits. Nur dass ich bspw. eine Funktion get() möchte, welche je nachdem ob das Objekt der HTTP-Request (zB. 16 Objekte werden angefordert, welche dann Objekt für Objekt ausgelesen werden und dann in eine Klasse gefüllt werden) eine Playlist oder ein Track ist.

    Nochmal was ich erreichen möchte, denn wir sind da glaub ich ein bisschen abgekommen:

    class Base {
        public:
    		QPixmap getArtwork(void);
    		std::string getTitle(void);
    		std::string getUsername(void);
    };
    
    class Track : public Base {
        public:
            std::string getStreamURL(void);
    };
    
    class Playlist : public Base {
        public:
            int getTrackCount(void);
    		std::vector<Track> tracks;
    };
    
    class Dashboard {
    	public:	
    		bool isTrack(void);
    		Track track;
    		Playlist playlist;
    
    		//Pseudo - Ziel
    		Track/Playlist get(void) {
    			if(isTrack())
    				return Track;
    			else
    				return Playlist;
    		}
    };
    


  • Sry, falscher Code (könnte ein Mod bitte diese zwei zusammenführen? :)):

    Edit v. Arcoth: Oben reineditiert.



  • Wo ist jetzt das Problem?
    Du kannst z.B. entweder boost::variante<Track, Playlist> als Returntyp [*] verwenden oder sowas wie std::unique_ptr<Base> .

    Dass eine Funktion nur einen Returntyp haben kann ist dir wohl hoffentlich klar ...?

    *: Natürlich kannst du mit einem der beiden genannten Typen auch deine drei Member ersetzen.



  • hustbaer schrieb:

    Wo ist jetzt das Problem?
    Du kannst z.B. entweder boost::variante<Track, Playlist> als Returntyp [*] verwenden oder sowas wie std::unique_ptr<Base> .

    Könntest Du mir da bitte mal ein Beispiel schreiben oder den Code unten verbessern? Denn ich bekomme das so nicht hin.

    hustbaer schrieb:

    Dass eine Funktion nur einen Returntyp haben kann ist dir wohl hoffentlich klar ...?

    Ist mir klar.

    Hier mal der Code:

    class Dashboard {
    	public:	
    		bool isTrack(void) {
    			return true; //Zwecksmäßig
    		}
    		Track track;
    		Playlist playlist;
    		boost::variant<Track, Playlist> dat;
    
    		Dashboard() {
    			if(isTrack())
    				dat = track;
    			else
    				dat = playlist;
    		}
    
    		class visitor1 : public boost::static_visitor<Track> {
    			public:
    				Track operator()(Track t) {
    					return t;
    				}
    
    		};
    
    		class visitor2 : public boost::static_visitor<Playlist> {
    			public:
    				Playlist operator()(Playlist p) {
    					return p;
    				}
    		};
    
    		class visitor3 : public boost::static_visitor<Track>, boost::static_visitor<Playlist> {
    			public:
    				Track operator()(Track t) {
    					return t;
    				}
    				Playlist operator()(Playlist p) {
    					return p;
    				}
    		};
    


  • get() sieht so aus:

    boost::variant<Track, Playlist> get(void) {
    	if(isTrack())
    		return dat.apply_visitor(visitor1());
    	else
    		return dat.apply_visitor(visitor2());
    }
    


  • @heyo
    Ich weiss ja immer noch nicht was du eigentlich hinbekommen willst.
    Du schreibst "hier mal der Code". Schön. Und?
    Wobei genau möchtest du Hilfe?



  • Du hattest ja geschrieben ich solle boost::variant oder std::unique_ptr verwenden. Nun habe ich es mit boost::variant versucht, jedoch weiß ich nicht mehr weiter.
    Den Code den ich gepostet habe lässt sich fehlerfrei kompilieren, jedoch funktioniert das nicht so wie in den boost Docs.

    Wie es in den Docs steht:

    boost::variant< int, std::string > u("hello world");
    std::cout << u; // output: hello world
    

    Wie ich es versucht habe:

    boost::variant<Track, Playlist> get(void) {
        if(isTrack())
            return dat.apply_visitor(visitor1());
        else
            return dat.apply_visitor(visitor2());
    }
    
    Dashboard ds;
    ds.get().getStreamURL(); //Kein member vorhanden
    Track t1 = boost::get<Track>(ds.get()); //Funktioniert; ist jedoch nicht das Ziel
    

    Nun, jetzt frage ich mich warum das Beispiel von den Docs einwandfrei funktioniert... Wegen der Bitverschiebung?



  • Beschreibe bitte in Worten, vollständig und verständlich, was du möchtest dass das Programm dann macht.

    Aus deinem Code kann ich nur entnehmen dass du getStreamURL auf etwas was ein Track oder eine Playlist sein kann aufrufen willst. Was natürlich nicht geht, weil ja nur Track diese Funktion hat. D.h. was du hier skizzierst ist inhärent unmöglich.

    heyo schrieb:

    Nun, jetzt frage ich mich warum das Beispiel von den Docs einwandfrei funktioniert... Wegen der Bitverschiebung?

    Willst du mich verarschen?



  • Sorry, ich konnte gestern nicht mehr klar denken...
    Btw. Danke mal an dieser Stelle, dass ihr mir noch antwortet. 🙂

    Gut, ich hoffe, dass ich hier jetzt alles reingepackt habe, damit es verständlich wird, was ich erreichen will:

    /Basisklasse, hier sind alle Funktionen/Variablen drinnen, welche für 'Track' & 'Playlist' gleich sind.
    class Base {
    	public:
    		QPixmap getArtwork(void);
    		std::string getTitle(void);
    		std::string getUsername(void);
    };
    
    //Hier sind alle Funktionen/Variablen drinnen, welche nur Track benötigt und auch nur Track aufrufen kann/soll.
    //Track kann alleine sein. Dh es wird nicht nur in 'Playlist' verwendet sondern ist auch alleinstehen.
    //Denk an ein Dashboard von Souncloud zB. Dort gibt es nicht nur Playlists welche Tracks enthalten. Dort ist es gemischt.
    class Track : public Base {
    	public:
    		std::string getStreamURL(void);
    };
    
    //Hier gilt das gleiche wie bei 'Track'
    class Playlist : public Base {
    	public:
    		int getTrackCount(void);
    		std::vector<Track> tracks;
    };
    
    //Fasst das Dashboard zusammen. Wenn das Item 1 der HTTP-Request ein Track ist, dann gibt 'isTrack()' true zurück, andernfalls wird false zurückgegeben. 
    //Man muss sich nun vorstellen, dass ich einen Container (std::vector<Dashboar> ds) habe und dort die ganzen Items (Tracks & Playlists) eingelesen habe.
    //Nun möchte ich eine Funktion haben, welche mir, je nachdem ob das Item (bspw. ds[0]) ein Track oder eine Playlist ist, entweder die Variable 'track' oder 'playlist' zurückgibt.
    //Ich habe es schon mit einem 'std::shared_ptr' versucht (Beispiel untetn), was auch funktioniert hätte, jedoch konnte ich da nur auf die gemeinsamen Methoden zugreifen.
    class Dashboard {
    	public:	
    		bool isTrack(void);
    		Track track;
    		Playlist playlist;
    		std::vector<std::shared_ptr<Base>> dat;
    
    		//Initialisiere 'dat'
    		Dashboard() {
    			dat.push_back(std::shared_ptr<Base>(new Track));
    			dat.push_back(std::shared_ptr<Base>(new Playlist));
    		}						
    
    		//Je nachdem ob nun 'track' oder 'playlist' gültig ist wird das Item zurückgegeben. 
    		//Funktioniert auch, jedoch kann ich wenn jetzt bspw. 'track' zurückgegeben wird nicht auf die Methode 'getStreamURL()' zugreifen.
    		std::shared_ptr<Base> get(void) {
    			if(isTrack())
    				return dat[0];
    			else
    				return dat[1];
    		}
    
    		//Nun, wie kann ich eine Funktion gestalten, sodass diese mir, je nachdem ob nun 'track' oder 'playlist' gültig ist, das richtige zurückgibt?
    
    };
    

    Ich hoffe jetzt ist es klar, was ich erreichen will.



  • Das was du willst, geht technisch nicht (C++ ist type-safe)! Entweder du mußt nach der Rückgabe den Typ überprüfen und casten, um die Track- bzw. Playlist-Funktionen aufzurufen, oder aber du packst alle Infos in eine (Basis-)Klasse (daher auch mein Link zum "Composite Pattern")...



  • Ok danke für deine Antwort. Dann wäre das Thema wohl geklärt. 🙂



  • Das Problem ist, dass dir nicht klar was es hier für ein grundsätzliches Problem gibt, ganz unabhängig von C++.

    Und nein, es ist jetzt immer noch nicht verständlich was du willst.
    Es geht um die **Verwendung** der Funktion get(), nicht um deren Implementierung. Wie du die aufrufen willst, und wie du das Ergebnis des Aufrufs dann weiter verwenden willst, und was dabei dann passieren soll, je 1x für wenn ein Track zurückkommt und 1x für wenn eine Playlist zurückkommt.


  • Mod

    @hustbaer: Merkwürdiger Tippfehler. Wie kann man "dein" statt "nein" schreiben? Die Tasten sind doch relativ weit auseinander? Oder ist's passiert weil es dem "und" direkt gefolgt ist, das ja mit einem d endet?



  • @Arcoth
    Danke für den Hinweis -> korrigiert 🙂

    Solche und ähnliche Tippfehler passieren mir in letzter Zeit öfters. Ist mir selbst schon aufgefallen dass ich öfter mal Tippfehler mache, die mit dem Treffen von falschen, benachbarten Tasten nicht zu erklären sind. Ich weiss aber nicht genau wieso. Ich könnte mir vorstellen dass es damit zu tun hat wie die einzelnen Bewegungsmuster, die man braucht um bestimmte Worte zu tippen, vom Gehirn "aufgefunden" werden, wenn man das entsprechende Wort tippen möchte. Und dass mein Hirn da manchmal "danebenhaut" und ein anderes, ähnliches (ähnlich klingendes) Wort "findet". Vielleicht wird es auch von der Abfolge der einzelnen Wörter beeinflusst - vielleicht schreibe ich viel öfter "und dein" als "und nein", keine Ahnung. Wäre interessant wie das wirklich geht, aber übersteigt meine Kompetenzen.

    Andere Theorie (würde in diesem Fall funktionieren, da ich aber kein anderes konkretes Beispiel mehr weiss kann ich nicht überprüfen ob das bei anderen vergleichbaren Tippfehlern auch passiert ist): Bei "und nein" muss ich nach dem "d" den letzten Buchstaben den ich mir der rechten Hand geschrieben habe wiederholen. Wenn ich statt dessen den letzten Buchstaben den ich mit der linken Hand geschrieben habe wiederhole, kommt "und dein" raus.

    ps: Ich hab grad "Testen" statt "Tasten" geschrieben. Auch nicht wirklich benachbarte Tasten. *facepalm* Damit wäre die 2. Theorie dann wohl wieder aus dem Rennen.



  • @hustbaer
    Also @Th69 hat doch verstanden was ich erreichen will.
    In meinem Post von gestern (mit dem Code) hab ich doch nur erläutert, was ich bereits versucht habe.
    Aber das ist jetzt ja nicht mehr von Bedeutung, da sowas mit C++ nicht funktioniert.


  • Mod

    heyo schrieb:

    Aber das ist jetzt ja nicht mehr von Bedeutung, da sowas mit C++ nicht funktioniert.

    Das funktioniert auch mit keiner anderen Sprache, zumindest so, wie du es derzeit darstellst.

    Du versuchst gerade einen Besen zu essen, weil er in einem Geschäft gekauft wurde, das auch Äpfel verkauft und dies deinem Modell nach daher beides das gleiche ist.




Anmelden zum Antworten