Newsgroup: it.comp.lang.c++
Titolo: >> operator overloading X Alex e per gli altri

Alex. Mettiamo che io voglia definire un insertion operator per un container
map<int, set<int> >:
istream& operator >> ( istream& ,  map<int, set<int> > );
in questo modo:
istream& operator >> ( istream& is,  map<int, set<int> > &_map ) { 
   istream_iterator iter( is ), eof;
   copy( is, eof,  _map.begin() );
   return is;
}
Affinché questa definizione sia compilata è necessario che sia definito
istream& operator >> ( istream& is,  map<int, set<int> >::value_type ).
(Credo.)
Ma non è possibile, in quanto  map<int, set<int> >::value_type::first_type è
const;
Oppure, invece di definire l'insertion operator, potrei:
ifstream infile( "file name" );
istream_iterator iter( infile ), eof;
map<int, set<int> > my_map( iter, eof  );
Mi piacerebbe conoscere il tuo pensiero.
Sergio
do...@insinet.it

Sergio Piccioni wrote in message <707vdm$638
    [snip]
: istream& operator >> ( istream& is,  map<int, set<int> > &_map )
:   istream_iterator iter( is ), eof;
:   copy( is, eof,  _map.begin() );
:   return is;
:}
:
:Affinché questa definizione sia compilata č necessario che sia definito
Anzitutto occorre cambiarla, perche` istream_iterator non e` una
classe ma un template (e non mi e` chiaro con quale parametro
tu intenda istanziarlo); in secondo luogo, occorre cambiarla ancora
perche` il primo e il secondo parametro di copy devono avere lo
stesso tipo (forse intendi passare iter dove hai scritto is...?).
Inoltre, occorre cambiarla (almeno) una terza volta perche` il
terzo parametro di copy deve essere un iteratore di inserimento
(e quello che hai scritto non lo e`), o, se no, deve garantire di
poter essere incrementato tante volte quante ne occorre perche`
il primo parametro, ripetutamente incrementato, divenga eguale
al secondo (e qui non abbiamo nessuna garanzia del genere);
e in ogni caso dev'essere tale da potere essere dereferenziato
con * ottenendo un lvalue assegnabile.
Usando come terzo parametro un insert_iterator<map< eccecc
(sarebbe sensato usare typedef per tipi cosi` complicati...!),
i problemi visti in questo paragrafo possono essere rimediati,
ma a questo punto stiamo facendo tante di quelle modifiche
che non mi sembra piu` sensato cercare di divinare quali
fossero le intenzioni dell'autore di questa funzione.
La semantica che si vuole ottenere dalla funzione stessa e`
poi particolarmente oscura.  Supponiamo che lo stream di
input sia composto solo da rappresentazioni di interi in base
decimale, separati da spazi (se vi fossero altri caratteri,
l'operazione di input fallirebbe -- sospetto, anzi, che si
potrebbe verificare un "loop infinito", ma non ho esaminato
la questione in dettaglio); dove si intende che vadano a
finire quegli interi?  Il primo come unica chiave della map,
tutti gli altri a comporre il set che vi corrisponde...?
: istream& operator >> ( istream& is,  map<int, set<int> >::value_type ).
: (Credo.)
: Ma non č possibile, in quanto  map<int, set<int> >::value_type::first_type č
: const;
Se il problema fosse tutto qui, basterebbe usare come parametro
dell'istream_iterator un tipo intermedio tale che lo si possa convertire
in value_type (altro non occorre, per l'insert_operator che penso si
voglia usare come terzo argomento di copy, se non che il container
su cui lo si istanzia supporti un adeguato metodo insert con un
iterator come primo argomento e un const value_type& come
secondo argomento).
: Oppure, invece di definire l'insertion operator, potrei:
:
: ifstream infile( "file name" );
: istream_iterator iter( infile ), eof;
: map<int, set<int> > my_map( iter, eof  );
Qui abbiamo ancora alcuni dei problemi precedenti, e in
particolare quello piu` grave relativo all'oscurita` della
semantica desiderata, nonche` quello relativo al fatto che
istream_iterator e` un template e qui non e` detto su che
tipo lo si voglia istanziare (presumibilmente, occorrera` un
tipo intermedio analogo a quello del caso precedente).
: Mi piacerebbe conoscere il tuo pensiero.
Io penso che sarebbe simpatico decidere prima quale
esatta semantica si voglia ottenere da questa operazione
di input (quale sia il formato previsto dello stream d'ingresso,
come si intendano delimitati fra loro le chiavi e i contenuti
della mappa) e solo in un secondo tempo studiare il modo
di ottenerla.
In questo caso, se e` proponibile un formato di input
orientato alla linea, uno schema naturale parrebbe essere:
le linee vuote o bianche sono saltate, le altre devono
contenere N interi, con N>0, di cui il primo e` la chiave
nella mappa, gli altri N-1 (anche 0) costituiscono gli
interi appartenenti al set che interessa.  Se si vuole un
input orientato alla linea, allora qualcosa del tipo...:
    string line;
    while(getline(is,line)) {
        istringstream iss(is);
        int key;
        if(iss>>key) {    // linea non vuota, procediamo
            set<int> si;
            int i;
            while(iss>>i) si.insert(i);
            _map[key] = si;
        }
    }
sembra l'approccio piu` lineare, anche se, naturalmente,
volendo, nulla impedisce di complicarsi la vita usando un
complesso di istream_iterator, insert_iterator, e copy,
per lo stesso lavoro che la linea "while(iss>>i) si.insert(i);"
gia` compie egregiamente:-).  Piu` seriamente, puo`
interessare diagnosticare (magari con exception?)
irregolarita` sull'input, tipo duplicazioni di chiavi o anche
duplicazioni di elementi in un dato insieme (la diagnosi
di errori del genere sull'input, naturalmente, e` sempre
un fattore di complicazione, se considerata necessaria).
Alex