Standard-Insert-Iteratoren mit sinnlosen Typedefs
-
Definition des Klassentemplates
std::back_insert_iterator:template <class Container> class back_insert_iterator : public iterator<output_iterator_tag,void,void,void,void,void> { // ... }Weiss jemand, warum dort überall
voidsteht und die ganze Typinformation über Bord geworfen wird? Warum hätte man nicht die Typdefinitionen des unterliegenden Containers nehmen können?Das zwingt mich nämlich zu unnötigen Spezialisierungen, wenn ich den Typ hinter einem Iterator herausfinden will:
template <typename Iterator> struct IteratorValueType { typedef typename std::iterator_traits<Iterator>::value_type Type; }; template <class Container> struct IteratorValueType< std::front_insert_iterator<Container> > { typedef typename Container::value_type Type; }; template <class Container> struct IteratorValueType< std::back_insert_iterator<Container> > { typedef typename Container::value_type Type; }; template <class Container> struct IteratorValueType< std::insert_iterator<Container> > { typedef typename Container::value_type Type; };
-
-
Vielen Dank für die Antwort. Ich hätte eher vermutet, der Grund würde in die Richtung gehen "Container brauchen so kein
value_typeals Typedef → weniger Anforderungen". So wie ich den Thread auf Stackoverflow verstehe, ist die Argumentation folgendermassen:Da
value_typeden Werttyp des dereferenzierten Iterators*itrzurückgibt und Output-Iteratoren nicht zwingend eine sinnvolle Dereferenzierung besitzen, sollvalue_typebei Output-Iteratoren immervoidsein.Aber wäre es nicht sinnvoller gewesen,
value_typeim Falle von Output-Iteratoren etwas weiter zu fassen und damit den Typ zu bezeichnen, in den geschrieben wird? Mir ist bewusst, dass es sich dabei nicht um eine Sequenz handeln muss, ausgegebene Elemente können schliesslich ohne Speicherung unmittelbar verarbeitet werden. Trotzdem muss zu dieser Verarbeitung der Typ des Elements bekannt sein.Diesen Elementtypen kann man momentan leider nicht ohne Weiteres bestimmen, wenn ein beliebiger Output-Iterator vorliegt.
-
Nexus schrieb:
Trotzdem muss zu dieser Verarbeitung der Typ des Elements bekannt sein.
Diesen Elementtypen kann man momentan leider nicht ohne Weiteres bestimmen, wenn ein beliebiger Output-Iterator vorliegt.
Weil - so wie ich das verstehe - ein Output-Iterator keinen Element-Typ haben muss.
Man könnte z.B. vom "
operator *" einen Proxy zurückgeben, der einen Template-Zuweisungsoperator hat.
z.B. um in Streams zu schreiben oder was auch immer.Vermutlich hätte man es auch so regeln können, dass
value_typefür Output-Iteratoren die genau einen fixen Typ "haben" genau als dieser Typ definiert sein muss, und nur für Output-Iteratoren auf die das nicht zutrifftvoid.
Evtl. hätte man die entsprechenden Typedefs auch einfach weglassen können, und das Iterator-Konzept soweit abändern, dass eben nicht jeder (Output-)Iterator einvalue_typeTypedef haben muss.Warum das nicht so gemacht wurde weiss ich auch nicht

-
hustbaer schrieb:
Weil - so wie ich das verstehe - ein Output-Iterator keinen Element-Typ haben muss.
Man könnte z.B. vom "
operator *" einen Proxy zurückgeben, der einen Template-Zuweisungsoperator hat.
z.B. um in Streams zu schreiben oder was auch immer.Du gehst hier aber davon aus, dass der "Element-Typ", falls man einen definieren könnte, gleich dem Typ des dereferenzierten Iterators sein müsste. Ich frage mich eher, warum der
value_typenicht von Anfang an allgemeiner aufgefasst wurde. Man hätte sich vielleicht nicht so stark an Input-Iteratoren orientieren sollen.Denn meistens werden Output-Iteratoren so verwendet:
*itr++ = value;Meiner Meinung nach wäre es folglich am sinnvollsten, wenn
value_typedem Parametertyp vondecltype(*itr)::operator=entspräche (allfällige Referenzen und
constentfernt). Denn diese Beziehung kann auf Proxies ebenso angewendet werden wie auf herkömmliche Container-Iteratoren – schliesslich muss der Operand des Zuweisungsoperators (im Beispielvalue) zu jenem Typ kompatibel sein, wenn er durch den Iterator ausgegeben wird. Jedoch sehe ich Probleme in Verbindung mit mehrerenoperator=-Überladungen.Die momentane Regel,
value_typesolle bei Output-Iteratorenvoidsein, ist nicht nur hinderlich, sondern auch inkonsistent. Spätestens wenn es sich um einen kombinierten Iterator (z.B. Forward-Iterator) handelt, mussvalue_typewegen der Input-Iteratoren einen sinnvollen Typ besitzen.
-
Nexus schrieb:
Denn meistens werden Output-Iteratoren so verwendet:
*itr++ = value;Meiner Meinung nach wäre es folglich am sinnvollsten, wenn
value_typedem Parametertyp vondecltype(*itr)::operator=entspräche (allfällige Referenzen und
constentfernt). Denn diese Beziehung kann auf Proxies ebenso angewendet werden wie auf herkömmliche Container-Iteratoren – schliesslich muss der Operand des Zuweisungsoperators (im Beispielvalue) zu jenem Typ kompatibel sein, wenn er durch den Iterator ausgegeben wird. Jedoch sehe ich Probleme in Verbindung mit mehrerenoperator=-Überladungen.Ich hab' ja geschrieben "einen Proxy zurückgeben, der einen Template-Zuweisungsoperator hat".
Ob jetzt überladungen oder nen Template-Zuweisungsoperator ist egal, kommt aufs selbe raus.Die momentane Regel, value_type solle bei Output-Iteratoren void sein, ist nicht nur hinderlich, sondern auch inkonsistent. Spätestens wenn es sich um einen kombinierten Iterator (z.B. Forward-Iterator) handelt, muss value_type wegen der Input-Iteratoren einen sinnvollen Typ besitzen.
Ist denn vorgeschrieben dass value_type für Output-Iteratoren immer void sein muss? Wenn ja, dann ist ein Forward-Iterator eben kein Output-Iterator. Das wäre natürlich etwas seltsam.
-
hustbaer schrieb:
Ich hab' ja geschrieben "einen Proxy zurückgeben, der einen Template-Zuweisungsoperator hat".
Ob jetzt überladungen oder nen Template-Zuweisungsoperator ist egal, kommt aufs selbe raus.Ah sorry, von der Seite hab ich das gar nicht gesehen (die Problematik ist mir erst im Nachhinein eingefallen, daher der Edit). Du hast natürlich Recht, der Typ wäre auch hier nicht eindeutig.
hustbaer schrieb:
Ist denn vorgeschrieben dass value_type für Output-Iteratoren immer void sein muss? Wenn ja, dann ist ein Forward-Iterator eben kein Output-Iterator. Das wäre natürlich etwas seltsam.
Ja, so habe ich das verstanden, deshalb meine Skepsis. Hier die Stelle im Standard:
§24.3.1/1 Iterator traits schrieb:
To implement algorithms only in terms of iterators, it is often necessary to determine the value and difference types that correspond to a particular iterator type. Accordingly, it is required that if Iterator is the type of an iterator, the types
iterator_traits<Iterator>::difference_type iterator_traits<Iterator>::value_type iterator_traits<Iterator>::iterator_categorybe defined as the iterator’s difference type, value type and iterator category, respectively. In the case of an output iterator, the types
iterator_traits<Iterator>::difference_type iterator_traits<Iterator>::value_typeare both defined as void.