Iterator Frage: Container Abstrahieren
-
Z2 schrieb:
...
C++ != Java
...Naja, wenn er unbedingt einen "Laufzeit-kontrollierten Container" (wie es sie in schon Java gibt) bauen möchte, kann er das ja tun - ich persönlich halte das zwar für einen unnötigen Rückschritt, aber das bedeutet ja noch nicht, dass es nicht ginge.
Letztlich würde ich dann aber komplett die Java-Variante durchziehen und mit void* bzw. ContainerItemBase* und entsprechenden casts arbeiten.@sapiens.dyslexia: Wieso ist Dir Laufzeitdefinition/Polymorphie so wichtig, dass es Compiletime-Definition nicht tut ?
Habe ich richtig verstanden: Du willst erst zur Laufzeit entscheiden, welcher Container verwendet wird .... und zwar bei STL-Containern, die zur Compilezeit definiert werden ?Gruß,
Simon2.
-
Z2 schrieb:
@Mr. N: Ok, schön gewrappt. Aber wie übergibst du deinen Iterator nun an einen Algorithmus?
Indem ich ihn übergebe:
algorithmus_der_nur_einen_iterator_braucht(it);Das nennt man Parameterübergabe. Das ist so ein ganz fieser Trick von C++, mit dem man viele böse Hacks machen kann. </sarkasmus>
Im Ernst: Ich übergebe iterator_proxy<T> und das wars dann. Es gibt kein Problem.
Übrigens halte ich es für vollkommen irrelevant, was Java-typisch ist und was nicht. Iteratoren nicht polymorph zu machen war eine bewusste Entscheidung des Komitees (Grund war bestimmt die Geschwindigkeit) und übrigens ein Kompromiss. Und ich muss zugeben, ich habe meine heute gebauten iterator_proxys zwar noch nie verwendet, aber vielleicht wäre das an manchen Stellen gut gewesen.
-
Wir haben halt Templates, der Algos müssen keine polymorphen Iteratoren verlangen. Hätten wir keine Templates, hätten die Algos sicherlich einen Iterator-Basistyp verlangt.
-
Artchi schrieb:
Die Container lassen sich nicht einfach beliebig austauschen.
Du hast das Iterator-Pattern nicht verstanden. Bitte nochmal lesen.
@Simon2:
Diese Anforderung ist ganz normal. Simpelstes Beispiel: Plugins. Warum sollte ich einem Plugin vorschreiben dass es seine Daten als vector speichert? Ich definiere da lieber "muss forward iteratoren anbieten" und fertig.
-
Shade Of Mine schrieb:
Artchi schrieb:
Die Container lassen sich nicht einfach beliebig austauschen.
Du hast das Iterator-Pattern nicht verstanden. Bitte nochmal lesen.
Dann kannst du mir sicherlich sagen, warum std::list eine eigene sort-Methode braucht? Wie kann ich also std::sort eine list übergeben? Ich kann zwar mit einem Iterator auf einen Container rumwandern, aber ich kann nochlange nicht beliebig alles mit einem beliebigen Container machen.
Kann aber auch sein, das ich es wirklich nicht verstanden habe, dann wäre ne Lösung für ein einfaches Beispiel wie std::sort und std::list super. Danke!

-
Shade Of Mine schrieb:
...
@Simon2:
Diese Anforderung ist ganz normal. Simpelstes Beispiel: Plugins. Warum sollte ich einem Plugin vorschreiben dass es seine Daten als vector speichert? Ich definiere da lieber "muss forward iteratoren anbieten" und fertig.Aho !

Ich hatte das immer von der andern Seite betrachtet (sprich: Er will über seinen STL-Container einen "polymorphen Stub" implementieren und mir fiel kein Grund dafür ein).Sowas kann man natürlich machen. Ob man sowas dann aber tatsächlich mit "Standardpolymorphie" und nicht mit "technischeren Methoden", weiß ich nicht.
Aber Danke für das Beispiel.
Gruß,
Simon2.
-
Artchi schrieb:
Dann kannst du mir sicherlich sagen, warum std::list eine eigene sort-Methode braucht?
weil das design kacke ist?
list sollte std::sort spezialisieren fuer seine eigenen iteratoren. oder genereller: sort sollte fuer bidirectional iteratoren spezialisiert sein um auch so einen container sortieren zu koennen.
aber das tut nichts zur sache.
Lies das Iterator Pattern.Wie kann ich also std::sort eine list übergeben? Ich kann zwar mit einem Iterator auf einen Container rumwandern, aber ich kann nochlange nicht beliebig alles mit einem beliebigen Container machen.
Du hast das Iterator Pattern nicht verstanden.
Es geht nicht darum dass du alles mit allem machen kannst. Sondern dass du aequivalente Collections untereinander tauschen kannst.
zB wenn random access iteratoren die anforderung sind, dann braucht man einen container der das unterstuetzt. Ein stack waere zB ungeeignet hier als drop in replace zu dienen.
ABER:
ich kann std::vector und boost::array frei tauschen. Beide erfuellen meine Anfoerderungen an die Collection.Das ist das Iterator-Pattern.
Ich kann die Collections implementieren wie ich will. Sie muessen nur die Anforderung erfuellen.
Kommt dir das bekannt vor? nein? kleiner tipp:
Was ist denn Vererbung? Also eine virtuelle methode:class Base { public: virtual int get_random_number() = 0; };Hier kann ich von Base erben und get_random_number implementieren wie ich will, oder?
falsch:
class Derived : public Base { public: void get_random_number(int& num); };geht ja nicht.
jetzt denkst du dir sicher "na lol, ist doch logisch - du musst die anfoerdung erfuellen, dass ein int returned wird, die exception spezifikationen duerfen nicht lockerer sein als in base,..."
denk darueber mal nach.
ist es beim auswechseln der collections nicht genauso? ich muss nur ein paar anforderungen erfuellen - aber wie ich es implementiere ist meine sache.
-
Shade Of Mine schrieb:
Artchi schrieb:
Dann kannst du mir sicherlich sagen, warum std::list eine eigene sort-Methode braucht?
weil das design kacke ist?...
Manchmal sind die naheliegensten Antworten die besten.

Gruß,
Simon2.
-
Artchi schrieb:
Dann kannst du mir sicherlich sagen, warum std::list eine eigene sort-Methode braucht?
Naja, du kannst für so ziemlich alles std::stable_sort verwenden (was halt langsamer ist). Oder du schreibst dir deine eigene kleine sort Funktion (Template), und verwendest std::iterator_traits<T>::iterator_category um zwischen "random-access" und "bidirectional" Iteratoren zu unterscheiden.
Is natürlich schade dass es nicht im Standard enthalten ist, aber ist halt so. std::copy_if fehlt ja auch immer noch... (wird aber im nächsten Standard drinnen sein, std::copy_if mein' ich jetzt).
-
Vielen Dank für euere interessanten Antworten.
Shade of Mine hat mit seinem Beispiel direkt in's Schwarze getroffen, die Abstrakte Klasse soll ein Interface für eine Art Plugin bereitstellen. Dumm nur dass ich nicht daran gedacht hatte das zuerwähnen..Das Problem ließ sich durch einen Workaround umgehen: Ich habe einfach (die bisher einzige relevante) Methode, die auf den Iteratoren operiert, in das Plugin (das Interface der Abstrakten Klasse) einverleibt und die Iterator-returnenden-Methoden rausgeschmissen.
(Die neu einverleibte Methode bekommt eine Strategy zum Selektieren einer Menge von Elementen des Containers, weshalb die Flexibilität zumindest nicht vollständig eingeschränkt ist.)Noch eine Technische Frage zu Mr N's Wrapper:
algorithmus_der_nur_einen_iterator_braucht(it);Wie sollte denn die Deklaration der Funktion/Methode des algorithmus aussehen?
Sie muss doch den genauen Typ aller (des) Parameter enthalten, also wieder über templates angeben was für einen iterator_proxy, bzw selbst ein template sein.Wenn dem so ist, unterstützt die Lösung keine Polymorphie, es muss nach wie vor zur Kompilierzeit festgelegt werden welche Iteratoren unterstützt werden.
Auch lässt sich der Algorithmus dann nicht durch eine erbende Klasse überschreiben, wenn er denn selbst eine template-Funktion/Methode ist.Gruß