2013-04-23 2 views
16

In meinem Projekt möchte ich streamen in eine bestimmte Art von Werten teilen, so dass ich implementieren eine Template-Funktion alsWarum ist der value_type/difference_type/pointer/reference von back_insert_iterator/front_insert_iterator/insert_iterator alle ungültig?

template <typename TElem, typename TOutputIter> 
TOutputIter SplitSpace(std::istream& IS, TOutputIter result) 
{ 
    TElem elem; 
    while (IS >> elem) 
    { 
     *result = elem; 
     ++result; 
    } 
    return result; 
} 

ich denke, das, da ich es die Art der TElem explizit angegeben haben, wenn Sie anrufen umständlich . Zum Beispiel muss ich schreiben:

std::vector<int> v; 
SplitSpace<int>(std::cin, back_inserter(v)); 
// I want to it to be SplitSpace(std::cin, back_inserter(v)); 

Ich habe versucht, den Werttyp aus einer (Schablone) Iterator und std::iterator_traits verwendet wie folgt zu erhalten:

template <typename TOutputIter> 
TOutputIter SplitSpace(std::istream& IS, TOutputIter result) 
{ 
    typename std::iterator_traits<TOutputIter>::value_type elem; 
    while (IS >> elem) 
    { 
     *result = elem; 
     ++result; 
    } 
    return result; 
} 

jedoch die oben genannten Codes funktionieren nicht für back_insert_iterator. Ich überprüfte die Quellcodes von back_insert_iterator/front_insert_iterator/insert_iterator in std Namensraum und fand die value_type/difference_type/pointer/reference sind alle void.

Ich würde gerne wissen, warum diese Typen alle void sind, gibt es eine Überlegung dafür? Eine andere Frage ist, dass es möglich ist, die SplitSpace Funktion zu implementieren, ohne explizit den Elementtyp anzugeben, wenn es aufgerufen wird? Vielen Dank.

+1

Sie sind Art von nur Iteratoren schreiben, welchen anderen Typ sollten diese typedefs haben? – PlasmaHH

+0

Nicht "irgendwie". Sie sind OutputIterators, d. H. Nur schreibend und nicht wiederholbar. Noch +1 für interessante Frage – sehe

+0

Definitiv seltsam, es scheint keinen Grund zu geben, den 'typedef' zu zerlegen, wenn sie sowohl zum Extrahieren von * als auch zum Einfügen von Elementen verwendet werden können ... –

Antwort

2

AFAIK, Sie sollten in der Lage sein, die container_type aus dem Iterator zu erhalten, von dem Sie in der Lage sein sollten, eine zu erhalten. Sie möchten sich wahrscheinlich irgendwann für eine pair spezialisieren. Dies sollte Teil zwei beantworten, wie für den ersten Teil; nicht sicher ...

+0

Wie erhalten Sie den Containertyp von einem Iterator (nicht jeder Output-Iterator hat tatsächlich einen Containertyp)? –

+0

@ChristianRau, sollte dies anscheinend für die aufgelisteten Iteratoren gelten: http://en.cppreference.com/w/cpp/iterator/front_insert_iterator – Nim

+0

.... bedeutet nicht, dass Ihr benutzerdefinierter Iterator namens '' Bob wird diese Funktionalität unterstützen ... das ist Ihr Vorrecht ... – Nim

3

Wie in den Kommentaren von Luc erwähnt, was Sie mit der Standardbibliothek leicht getan tun wollen werden können:

std::vector<int> v; 
std::copy(std::istream_iterator(std::cin) 
     , std::istream_iterator() 
     , std::back_inserter(v)); 
3

value_type nicht viel Sinn im Fall von OutputIterators macht, weil Ein Ausgabe-Iterator bietet keinen Zugriff auf Werte und, was noch wichtiger ist, er akzeptiert eine Vielzahl von Werttypen.

Die einzige Voraussetzung für eine OutputIterator it ist, dass es muss der Ausdruck *it = ounterstützt, wo o einen Wert von einer Art ist, die in dem Satz von Typen, die (§24.2 der besonderen Iteratortyp von i beschreibbar sind. 1). Dies bedeutet, dass ein Ausgabe-Iterator potenziell eine Vielzahl von Typen akzeptieren kann: Beispielsweise kann operator* ein Proxy-Objekt zurückgeben, das operator= für eine Vielzahl von Typen überlädt. Was sollte value_type in diesem Fall sein?

Betrachten wir zum Beispiel die folgende Ausgabe Iterator:

struct SwallowOutputIterator : 
    public std::iterator<output_iterator_tag, void, void, void, void> 
{ 
    struct proxy // swallows anything 
    { 
     template <typename T> 
     void operator=(const T &) {} 
    }; 

    proxy operator*() 
    { 
     return proxy(); 
    } 

    // increment operators 
}; 

Es gibt keine vernünftige Wahl für value_type hier. Die gleichen Überlegungen gelten für pointer und reference_type. difference_type ist nicht definiert, da Sie den Abstand zwischen zwei Ausgabe-Iteratoren nicht berechnen können, da sie Single-Pass sind.

N.B .: Der Standard besagt explizit, dass insert_iterator und seine Geschwister von iterator<output_iterator_tag, void, void, void, void> erben müssen, also ist dies keine Besonderheit Ihrer Implementierung.

3

Falls Sie nur nach einem Weg suchen, um die TElem Vorlage param zu vermeiden, um anzugeben, können Sie diesen Ansatz verwenden:

template <typename TOutputIter> 
TOutputIter SplitSpace(std::istream& IS, TOutputIter result) 
{ 
    typedef typename TOutputIter::container_type::value_type TElem; 

    TElem elem; 
    while (IS >> elem) 
    { 
     *result = elem; 
     ++result; 
    } 
    return result; 
} 

... natürlich, je nachdem, welche TOutputIter Typen, die Sie vorgeben zu verwenden , sollten Sie diesen Ansatz nicht verwenden.

+0

Danke, das sollte die akzeptierte Antwort sein, denke ich. –

Verwandte Themen