Minule jste dostali na rozmyÜlenou, jak co nejjednoduÜeji s pomocφ prost°edk∙ STL napsat funkci, kterß otestuje, zda danΘ slovo je Φi nenφ palindrom (tj. od zaΦßtku i od konce se Φte stejn∞). Zde je elegantnφ °eÜenφ
bool
je_palindrom(const string & slovo)
{
áá return equal(slovo.begin(), slovo.end(), slovo.rbegin());
}
ZaΦneme trochu netradiΦn∞, popisem funkce copy. Tato funkce vypadß nßsledovn∞
template<typename InputIterator,
áááááááá typename
OutputIterator>
OutputIterator copy(InputIterator prvni, InputIterator
posledni,
áááááááá OutputIterator
kam)
{
áá while ( prvni != posledni ) *kam++ = *prvni++;
áá return kam;
}
Tato funkce kopφruje data z rozsahu [prvni, posledni), do rozsahu [kam, kam + (posledni - prvni)). Zkusme si te∩ jeden p°φklad û chceme provΘst spojenφ dvou vektor∙ tφm, ₧e jeden nakopφrujeme za druh²
vector<int>
v;á // + vlo₧enφ n∞jak²ch prvk∙
vector<int>
w;á // + vlo₧enφ n∞jak²ch prvk∙
// spojenφ: k w prikopirujeme v
copy(v.begin(), v.end(), w.end());á // !!! CHYBA
Pokud jste u₧ n∞kdy n∞co takovΘho zkusili, urΦit∞ vßm to nefungovalo sprßvn∞. ProΦ? Proto₧e funkce copy nepracuje s kontejnery (v naÜem p°φpad∞ jde o t°φdu vector), ale s iterßtory na t∞chto kontejnerech. Nemß tudφ₧ kredit k p°idßvßnφ prvk∙ do kontejneru û a o to jsme se tu pokusili.
Jin²mi slovy, funkce copy funguje v takzvanΘm p°episovacφm (overwrite) re₧imu, to znamenß, ₧e p°episuje ji₧ existujφcφ prvky nov²mi hodnotami. Za koncem kontejneru, poΦφnaje iterßtorem end(), ji₧ ₧ßdnΘ prvky nejsou, a proto p°φkaz oznaΦen² t°emi vyk°iΦnφky m∙₧e zp∙sobit i havßrii programu...
Existuje vÜak zp∙sob, jak p°inutit funkci copy k prßci v takzvanΘm vklßdacφm (insert) re₧imu. Musφme vÜak pou₧φt specißlnφ v²stupnφ iterßtory û vklßdacφ iterßtory.
Jak takovß v∞c funguje? P°edem si musφme uv∞domit, ₧e jde o v²stupnφ iterßtory (viz [3]), tak₧e mno₧ina podporovan²ch operacφ je znaΦn∞ omezena. Za druhΘ, jde nßm o to, p°evΘst p°φkaz
*kam++ = neco;
na volßnφ metody kontejneru pro vlo₧enφ prvku. M∙₧e jφt o metodu insert, push_back, nebo push_front podle toho, jestli chceme vklßdat prvky kamkoli, na konci, nebo na zaΦßtku kontejneru. PopφÜeme si zde konstrukci v²stupnφho iterßtoru, kter² pou₧φvß metodu insert. Je jasnΘ, ₧e takov² iterßtor musφ uchovßvat odkaz na kontejner a iterßtor, kter² urΦuje, kam se budou vklßdat prvky. S pou₧itφm standardu C++, sekce 24.4.2.5 :
template <typename Container>áá // (1)
class insert_iterator
á : public iterator<output_iterator_tag,
void, void, void, void>á // (2)
{
protected:
áá Container *
container;ááá // (3)
áá typename Container::iterator
iter;áá // (4)
public:
áá typedef Container
container_type;áá // (5)
áá insert_iterator(Container
& x,
áááááááááááááááááá typename
Container::iterator i);á // (6)
áá insert_iterator<Container>
&
ááááá operator
=(typename Container::const_reference value);á
// (7)
áá insert_iterator<Container>
& operator *();á // (8)
áá // ...
};
(1) Metoda insert je povinnou souΦßstφ v∞tÜiny kontejner∙, proto je rozumnΘ parametrizovat vklßdacφ iterßtor typem kontejneru. O rozdφlech mezi vklßdßnφm do r∙zn²ch typ∙ kontejner∙ pohovo°φme za chvφli.
(2) Jde o v²stupnφ iterßtor. Rysy iterßtoru aktivujeme odvozenφm iterßtoru od t°φdy iterator. Vφce viz [4].
(3) Odkaz na kontejner.
(4) Iterßtor, kter² urΦuje, kam se bude vklßdat. Typ iterßtoru zφskßme tak, ₧e se zeptßme kontejneru na jeho typ iterßtoru tj. Container::iterator. KlφΦovΘ slovo typename je zde nutnΘ û napovφ p°ekladaΦi, ₧e jde o typ.
(5) Abychom se mohli vklßdacφho iterßtoru zeptat na typ kontejneru, do kterΘho vklßdß, je k dispozici tato vno°enß definice typu.
(6) Konstruktor: zadßme instanci kontejneru a nesingulßrnφ iterßtor (instanci) na tomto kontejneru. Slou₧φ k inicializaci atribut∙ (3) a (4).
Nynφ to nejd∙le₧it∞jÜφ: Jak implementovat operßtory (7) a (8)? Jak vφte z Φlßnku [3], operßtor dereferencovßnφ v²stupnφho iterßtoru m∙₧e vrßtit proxy, tj. zßstupnou t°φdu, jejφ₧ p°etφ₧en² operßtor = se postarß o ulo₧enφ prvku. A o to tu jde. Tento operßtor vrßtφ proxy, akorßt ₧e pro jednoduchost touto proxy bude t°φda insert_iterator osobn∞ (to je ale detail implementace, nikoli standardem na°φzenΘ chovßnφ...). Tak₧e t∞lo operßtoru (8) bude obsahovat jedin² p°φkaz
return *this;
Te∩ je jasnΘ, ₧e operßtor (7) se musφ postarat o vlo₧enφ prvku do kontejneru a aktualizaci atributu iter, nebo¥ vlo₧enφm prvku m∙₧e tento iterßtor ztratit platnost (nap°. kv∙li re-alokaci). Jeho t∞lo bude vypadat takto
iter = container->insert(iter, value); // (a)
++iter;áá // (b)
return *this;
(a) Ulo₧φme hodnotu value do kontejneru na pozici, urΦenou iterßtorem iter pomocφ metody insert. P°itom m∙₧e dojφt k re-alokaci, Φφm₧ by p∙vodnφ iterßtor iter ztratil platnost. NaÜt∞stφ metoda insert chyt°e vracφ iterßtor na v²slednou pozici, kam je ulo₧ena hodnota.
(b) Metoda insert uklßdß novΘ prvky do kontejneru p°ed prvek urΦen² jako mφsto vklßdßnφ. Abychom zajistili toto chovßnφ i pro vklßdacφ iterßtory, musφme postrΦit iter o jeden prvek dop°edu, tak aby odkazoval na p∙vodnφ prvek, p°ed kter² se majφ vklßdat novΘ.
Zb²vajφ jeÜt∞ oba operßtory ++. Jeliko₧ u₧ operßtory (7) a (8) vykryly vÜechnu pot°ebnou Φinnost, budou operßtory ++ hrßt mrtvΘho brouka: ₧ßdn² p°echod na dalÜφ prvek, jen
return *this;
Zb²vß jeÜt∞ oddiskutovat pou₧itφ metody insert u r∙zn²ch kontejner∙. Stejn∞ jako koncepty iterßtor∙ mßme i koncepty kontejner∙, viz Φlßnek [5]. Po₧adavky vklßdacφho iterßtoru na typ kontejneru spl≥ujφ dva koncepty (a samoz°ejm∞ vÜechny ostatnφ, kterΘ je zjem≥ujφ): posloupnost (Sequence) a set°φd∞n² asociativnφ kontejner (Sorted Associative Container), ka₧d² vÜak po svΘm. Zatφmco u posloupnostφ se nov∞ vklßdanΘ hodnoty v₧dy dostanou na (p°ed) mφsto, kterΘ je urΦeno iterßtorem iter, u set°φd∞n²ch asociativnφch kontejner∙ to neplatφ. Je to celkem pochopitelnΘ: Vklßdanß hodnota musφ padnout tam, kam pat°φ podle t°φdφcφho kritΘria. Parametr iter tam slou₧φ pouze jako pom∙cka (kam asi by to mohlo padnout), ale na v²slednΘm umφst∞nφ hodnoty nemß vliv.
Nynφ zp∞t k funkci copy. S pou₧itφm vklßdacφho iterßtoru bychom mohli napsat (a tentokrßt u₧ to bude v po°ßdku)
// spojenφ: k w prikopirujeme v
copy(v.begin(), v.end(),
ááá insert_iterator<vector<int>
>(w, w.end()));
Ale po°ßd je to moc slo₧itΘ. NaÜt∞stφ, stejn∞ jako u funktor∙, standard definuje p°φsluÜnou vytvo°ujφcφ funkci, kterß s vyu₧itφm pokroΦil²ch vlastnostφ C++ vytvo°φ pot°ebnou instanci vklßdacφho iterßtoru jen na zßklad∞ typ∙ argument∙.
template <typename Container, typename Iterator>
inline insert_iterator<Container>
inserter(Container& x, Iterator i)
{
áá return insert_iterator<Container>(x,
ááááááááá typename Container::iterator(i));
}
Vytvo°ujφcφ funkce inserter se postarß o vytvo°enφ instance vklßdacφho iterßtoru. Rovn∞₧ se pokusφ o konverzi iterßtoru i na po₧adovan² typ, kter²m je Container::iterator. Pomocφ vytvo°ujφcφ funkce zjednoduÜφme nßÜ k≤d na
// spojenφ: k w prikopirujeme v
copy(v.begin(), v.end(), inserter(w, w.end()));
Pou₧ili jsme obecn² vklßdacφ iterßtor aΦkoli nevklßdßme prvky doprost°ed, ale na konec posloupnosti. Proto bychom mohli pou₧φt vklßdacφ iterßtor zalo₧en² na metod∞ push_back. Princip je stejn² jako u t°φdy insert_iterator, ale s t∞mito rozdφly:
Jeliko₧ t°φda vektor je modelem konceptu Back Insertion Sequence a podporuje operaci push_back, m∙₧eme psßt (rovnou s vyu₧itφm vytvo°ujφcφ funkce)
// spojenφ: k w prikopirujeme v
copy(v.begin(), v.end(), back_inserter(w));á
// OK
Obdobn∞ jako na konec, m∙₧eme vklßdat prvky na zaΦßtek posloupnosti metodou push_front. Oproti vklßdßnφ na konec jsou tu tyto rozdφly
Jeden d∙le₧it² rozdφl nakonec: Zatφmco v p°φpad∞ vklßdßnφ na konec nebyl rozdφl mezi pou₧itφm obecnΘho vklßdacφho iterßtoru (insert_iterator) a iterßtoru back_insert_iterator, u vklßdßnφ na zaΦßtek posloupnosti to neplatφ. Ne₧ zaΦnete Φφst dalÜφ °ßdky, zkuste se zamyslet proΦ tomu tak je.
(Nejen) pro ty netrp∞livΘ, zde je vysv∞tlenφ: Iterßtor front_insert_iterator uklßdß prvky, tak jak p°ijdou, v₧dy na zaΦßtek, tak₧e jejich v²slednΘ po°adφ v posloupnosti je obrßcenΘ. P°i pou₧itφ vklßdacφho iterßtoru insert_iterator si tento pamatuje iterßtor na p∙vodnφ prvnφ prvek v posloupnosti po celou dobu vklßdßnφ. To znamenß, ₧e po°adφ vlo₧en²ch prvk∙ v posloupnosti bude odpovφdat po°adφ, v jakΘm byly vlo₧eny.
V∞tÜina STL generick²ch algoritm∙ pracuje v p°episovacφm (overwrite) re₧imu. To proto, ₧e p°i pou₧itφ iterßtor∙, kterΘ jim nabφdnou kontejnery, tyto algoritmy nemajφ kredit k modifikaci kontejneru (tj. poΦtu prvk∙ v kontejneru apod.) ale pouze k modifikaci prvk∙, na kterΘ odkazujφ iterßtory. STL vÜak nabφzφ prost°edek, kter² umo₧nφ algoritm∙m pracovat ve vklßdacφm (insert) re₧imu û vklßdacφ iterßtory. Pomocφ nich je mo₧nΘ do kontejner∙ p°idßvat novΘ prvky.
Na zßv∞r povφdßnφ o vklßdacφch iterßtorech se sluÜφ °φct, ₧e je i jejich vytvo°ujφcφ funkce zp°φstupnφme vlo₧enφm standardnφho hlaviΦkovΘho souboru <iterator>. Pro pou₧φvßnφ vklßdacφch iterßtor∙ si staΦφ pamatovat jen ty t°i vytvo°ujφcφ funkce.
A jeÜt∞ jedna rada: NaÜe pou₧itφ funkce copy k p°ipojenφ jednoho vektoru za druh² bylo zvoleno kv∙li vhodnΘ demonstraci funkce vklßdacφch iterßtor∙. Jinak (a lΘpe) lze tuto akci uskuteΦnit pomocφ metody insert
w.insert(v.begin(), v.end());
Jsou ale situace, kde funkce copy a vklßdacφ iterßtory p°edstavujφ elegantnφ °eÜenφ. Jeden takov² p°φklad poznßme zßhy, a₧ se trochu seznßmφme s iterßtory na vstupn∞/v²stupnφch datov²ch proudech.
DatovΘ proudy jazyka C++ (iostreams) p°edstavujφ dalÜφ zajφmavou mo₧nost aplikace iterßtor∙. Jednφm z d∙vod∙ zavedenφ koncept∙ vstupnφho a v²stupnφho iterßtoru je prßv∞ mo₧nost dßt STL generick²m algoritm∙m Üanci pracovat p°φmo s datov²mi proudy.
Zßkladnφ myÜlenkou iterßtoru na vstupnφm proudu je p°evedenφ operace p°φstupu k prvku s p°echodem na dalÜφ prvek *i++ na operaci Φtenφ z datovΘho proudu operßtorem >>. Je jasnΘ, ₧e takov² iterßtor bude modelem (nejv²Üe) vstupnφho iterßtoru. To plyne z toho, ₧e ji₧ p°eΦten² prvek nem∙₧e b²t znovu Φten (byl ji₧ z datovΘho proudu extrahovßn), a tudφ₧ tento iterßtor neumo₧≥uje vφcenßsobn² pr∙chod.
template <typename T,ááá // (1)
ááááááááá typename
charT = char, // (2)
ááááááááá typename
traits = char_traits<charT>,áá //
(3)
ááááááááá typename
Distance = ptrdiff_t>ááá // (4)
class istream_iteratoráá
// (5)
áá : public iterator<input_iterator_tag,
T,áá // (6)
áááááááááááááááá Distance,
const T*, const T&>
{
áá // ... uvedeny
jen specifickΘ slo₧ky
public:
áá typedef charT
char_type;áá // (7)
áá typedef traits
traits_type;á // (8)
áá typedef basic_istream<charT,traits>
istream_type;á // (9)
áá istream_iterator();á
// (10)
áá istream_iterator(istream_type&
s);á // (11)
};
(1) Typ vstupnφch dat, aneb jak mß iterßtor interpretovat vstupnφ data. Pokud chceme z proudu Φφst celß Φφsla, bude T nap°φklad int.
(2) Typ znaku datovΘho proudu. Obvykle char; pro znaky Unicode by to byl wchar_t.
(3) T°φda rys∙ popisujφcφ zßkladnφ typy a operace pro prßci se znaky a s posloupnostφ znak∙. Obvykle vystaΦφme s uveden²m implicitnφm argumentem.
(4) Typ rozdφlu iterßtor∙.
(5) JmΘno t°φdy
(6) Odvozenφm od t°φdy iterator aktivujeme rysy iterßtoru (t°φda iterator_traits).
(7) Definice typu, kterß umo₧≥uje zeptat se iterßtoru na typ znaku datovΘho proudu.
(8) To samΘ pro typ t°φdy rys∙ znaku datovΘho proudu.
(9) To samΘ pro typ datovΘho proudu.
(10) Implicitnφ konstruktor. Vytvo°φ iterßtor, kter² se bude tvß°it jako konec datovΘho proudu (end-of-stream). To mß v²znam p°i zadßvßnφ rozsahu Φtenφ.
(11) Konstruktor, kter²m se iterßtor äp°ipojφô k datovΘmu proudu.
Jak tento iterßtor funguje? Zkusme si jednoduch² vstup z p°φkazovΘ °ßdky. Nejd°φve vytvo°φme instanci iterßtoru na vstupnφm datovΘm proudu cin a pak p°eΦteme dv∞ celß Φφsla.
istream_iterator<int> i(cin);
int prvni
= *i++;
int druhΘ
= *i++;
JednotlivΘ metody iterßtoru si prßci rozd∞lily takto: konstruktor vytvo°φ instanci iterßtoru, p°ipojφ ji ke standardnφmu vstupnφmu proudu cin a naΦte pomocφ operßtoru >> prvnφ prvek do internφho atributu. Operßtor dereferencovßnφ * vrßtφ prvek ulo₧en² v internφm atributu. Operßtor ++ provede p°echod na dalÜφ prvek, tj. naΦte pomocφ operßtoru >> dalÜφ prvek do internφho atributu. Prvky jsou v datovΘm proudu odd∞leny takzvan²mi bφl²mi znaky (jeden nebo vφce mezer, tabulßtor∙, znak∙ konce °ßdku apod.).
A nynφ ji₧ d°φve slφbenΘ elegantnφ pou₧itφ vklßdacφch iterßtor∙. NaΦteme do vektoru data z datovΘho proudu (jde to i ze souboru, ale my se zde omezφme na standardnφ vstupnφ proud).
vector<int> v;
copy(istream_iterator<int>(cin),
áááá istream_iterator<int>(),
áááá back_inserter(v));
VÜimn∞te si zadßnφ vstupnφho rozsahu. P°edem nevφme kolik tam bude prvk∙. Vyu₧ijeme ale jednΘ vlastnosti t∞chto iterßtor∙: pokud se Φtenφ nezda°φ z jakΘhokoliv d∙vodu (nap°. konec souboru), pak se iterßtor zaΦne tvß°it jako iterßtor na konec datovΘho proudu, co₧ znamenß ukonΦenφ iterovßnφ. DalÜφ vlastnostφ je nemo₧nost zadat rozsah jinak ne₧ od zaΦßtku do konce datovΘho proudu.
Iterßtor na v²stupnφm datovΘm proudu je zalo₧en na myÜlence p°evedenφ operace zßpisu prvku *i = a na zßpis do datovΘho proudu pomocφ operßtoru <<. Stejn∞ jako v p°edchozφm p°φpad∞, tento iterßtor nenφ vφcepr∙chodov², tedy je modelem pouze konceptu v²stupnφho iterßtoru.
template <typename T,
ááááááááá typename
charT = char,
ááááááááá typename
traits = char_traits<charT> >
class ostream_iteratoráá
//á (1)
áá : public iterator<output_iterator_tag,áá
// (2)
áááááááááááááááááááá void,
void, void, void>
{
public:
áá // ... uvedeny
jen specifickΘ slo₧ky
áá ostream_iterator(ostream_type&
s);áá // (3)
áá ostream_iterator(ostream_type&
s, const charT * delimiter);á // (4)
áá ostream_iterator<T,charT,traits>&
operator=(const T& value);á //
(5)
};
(1) JmΘno t°φdy.
(2) Odvozenφm od t°φdy iterator aktivujeme rysy iterßtoru (t°φda iterator_traits). O zvlßÜtnostech rys∙ v²stupnφch iterßtor∙ jsme hovo°ili minule.
(3) Konstruktor, kter²m se iterßtor äp°ipojφô k datovΘmu proudu. ZapisovanΘ prvky nebudou nijak odd∞leny.
(4) Konstruktor, kter²m se iterßtor äp°ipojφô k datovΘmu proudu. Zßrove≥ se nastavφ odd∞lovaΦ (°et∞zec), kter² se vypφÜe po ka₧dΘm zapsanΘm prvku.
(5) Operßtor zßpisu prvku. Tentokrßt, na rozdφl od vstupnφho iterßtoru, mß tento na starosti v²stup prvku a p°φpadn∞ i o v²stup odd∞lovacφho °et∞zce, pokud byl tento zadßn v konstruktoru (4).
Ostatnφ operßtory (++, *) ned∞lajφ nic jinΘho ne₧ pouze vracφ *this. A jak to funguje? Pokud jste sledovali zdrojovΘ k≤dy na Chip CD, jist∞ vφte, jak vypsat na obrazovku (nebo i do souboru) pole prvk∙ bez napsßnφ smyΦky
int pole[5] = { 1, 1, 2, 3, 5 };
copy(pole,
pole + 5, ostream_iterator<int>(cout, ô ô));
Vypisujeme prvky pole do standardnφho v²stupnφho proudu cout. Prvky budou odd∞leny mezerou.
Pokud pot°ebujeme neformßtovan² vstup a v²stup znak po znaku, m∙₧eme pou₧φt iterßtory na vyrovnßvacφ pam∞ti datov²ch proud∙. I zde musφme rozliÜit vstup a v²stup. V nßsledujφcφch v²pisech t°φd uvßdφme jen ty slo₧ky, kterΘ vy₧adujφ vysv∞tlenφ.
template<typename charT,
áááááááá typename
traits = char_traits<charT> >
class istreambuf_iterator
áá : public iterator<input_iterator_tag,
charT,
áááááááááááááááááááá typename
traits::off_type,
áááááááááááááááááááá charT
*, charT &>
{
áá // ... uvedeny
jen specifickΘ slo₧ky
public:
áá istreambuf_iterator()á
// (1)
áá istreambuf_iterator(istream_type
& s) throw();á // (2)
áá istreambuf_iterator(streambuf_type
* s) throw();á // (3)
áá bool equal(istreambuf_iterator
& j);á // (5)
};
(1) Konstruktor, kter² vytvo°φ iterßtor na konec datovΘho proudu.
(2) Konstruktor, kter² se p°ipojφ k vyrovnßvacφ pam∞ti datovΘho proudu. V p°φpad∞, ₧e datov² proud je prßzdn² vytvo°φ iterßtor na konec proudu.
(3) To samΘ jako (2), ale s tφm, ₧e zadßme p°φmo vyrovnßvacφ pam∞¥.
(4) Rovnost dvou iterßtor∙ typu istreambuf_iterator: rovnajφ se kdy₧ jsou bu∩ oba iterßtorem na konec proudu, nebo ani jeden nenφ iterßtorem na konec proudu.
Narozdφl od formßtovanΘho vstupu, zde konstruktor nenaΦte ₧ßdn² znak. O naΦφtßnφ znak∙ se starß operßtor p°φstupu k prvku *. Ukß₧eme si jeden u₧iteΦn² p°φklad jak nejlΘpe naΦφst obsah (textovΘho) souboru do °et∞zce
ifstream
in(ôdata.txtö);
string
data((istreambuf_iterator<char>(in)),
ááááááá áááááistreambuf_iterator<char>());
Je to mnohem rychlejÜφ ne₧ pou₧itφ formßtovanΘho vstupu. ProΦ je prvnφ parametr v zßvorkßch se dozvφte p°φÜt∞.
Neformßtovan² v²stup znak po znaku zajistφ nßsledujφcφ v²stupnφ iterßtor
template <typename charT,
ááááááááá typename
traits = char_traits<charT> >
class ostreambuf_iterator
áá : public iterator<output_iterator_tag,
áááááááááááááááááááá void,
void, void, void>
{
áá // ... uvedeny
jen specifickΘ slo₧ky
public:
áá ostreambuf_iterator(ostream_type
& s);á // (1)
áá ostreambuf_iterator(streambuf_type
* s);á // (1)
áá ostreambuf_iterator
& operator =(charT c);á // (2)
áá bool failed()
const;á // (3)
};
(1) Konstruktory, kterΘ p°ipojφ iterßtor k v²stupnφ vyrovnßvacφ pam∞ti.
(2) Zde se odehrßvß zßpis znaku do proudu, ale jen v p°φpad∞, ₧e failed() vrßtφ false.
(3) Vracφ true, pokud se p°i n∞jakΘm p°edchozφm zßpisu (operßtor =) dosßhlo konce proudu; jinak vracφ false.
Ostatnφ operßtory pouze vracφ *this. Navß₧eme na p°edchozφ jednoduch² p°φklad: Kdy₧ u₧ jsme naΦetli textov² soubor, tak si ho te∩ znovu ulo₧φme
ofstream out(ômojedata.txtö);
copy(data.begin(), data.end(),
áááá ostreambuf_iterator<char>(out));
Deklaraci vÜech t∞chto iterßtor∙ na vstupn∞/v²stupnφch proudech nalezneme v hlaviΦkovΘm souboru <iterator>. Poslednφ dva jmenovanΘ jsou neprßvem podce≥ovßny a p°ehlφ₧eny. Pokud jde o neformßtovan² vstup nebo v²stup, jsou ale tou pravou volbou.
V p°φÜtφm zßv∞reΦnΘm dφlu dokonΦφme p°ehlφdku STL a vÜimneme si nejΦast∞jÜφch chyb a äpodraz∙ô, kterΘ s sebou pou₧φvßnφ iterßtor∙ p°inßÜφ.
Jaroslav Fran∞k
Infotipy
[1] Dokumentace STL od SGI: www.sgi.com\technology\stl
[2] J. Fran∞k, Iterßtory I, Chip 01/03
[3] J. Fran∞k, Iterßtory II, Chip 01/03
[4] J. Fran∞k, Iterßtory III, Chip 01/03
[5] J. Fran∞k, Nebojte se STL, Chip 12/01
[6] D. Musser et al., STL
Tutorial and Reference Guide, 2001
[7] N. Josuttis, The
C++ Standard Library, 1999