Newsgroup: it.comp.lang.c++
Titolo: C++: Manipolatori di stream... Aiuto

Salve a tutti,
sto imparando a programmare in C++ e mi sono imbattuto in un problema che
dovrebbe
essere, credo, di banale soluzione ma che sono riuscito a risolvere solo in
parte...
In pratica, vorrei riuscire a leggere dati da uno fstream da un file di
testo ignorando eventuali commenti
(ad es. ignorando la parte di una linea successiva alla sequenza "//")
In un primo momento avevo risolto il problema in questo modo
("Nocom_stream" sarebbe uno ifstream che ignora i commenti):
class Nocom_stream: public ifstream{
   private:
   void ignore_comment();
   public:
   Nocom_stream& operator>>(int& i) {
        ignore_comment();
        ifstream::operator>>(i);
        return *this;
    }
[...]
}
Ossia, uno stream che prima di leggere, ad es. un int, salta eventuali
commenti con la funzione ignore_comment();
In un primo momento funzionava, ma con un compilatore + aggiornato non
funziona più: evidentemente
il codice non rispetta al 100% gli standards...
Guardando degli esempi su libri di C++, mi sembra che la soluzione potrebbe
essere di definire
un manipolatore di stream, es.
file >> ignore_comments >> i;
che disabilita la lettura deicommenti, ma non so bene come fare...
Qualcuno può darmi qualche dritta? (e un po' di pseudo-codice)
Grazie a tutti per l'attenzione...
Stefano Zanobi

 Qualcuno può darmi qualche dritta? (e un po' di pseudo-codice)
Quello che vuoi implementare mi pare una buona soluzione.
Se non ricordo male, puoi definire un manipolatore nel seguente modo:
    std::istream& ingore_comments(std::istream& in)
    {
        leggi caratteri finche:
        -arrivi alla fine dell'input (in.eof()),
        -ottieni un errore (in.fail()),
        -il carattere non è un white-space (isspace(char c))
        verifica l'ultimo carattere che hai letto:
        -se non è il tuo carattere di inizio commento, rimettilo nello
stream (in.unget()) ed esci.
        -se è il tuo carattere di inizio commento leggi il resto della riga.
    }
Un rifermento utile per me è stato 
http://www.cplusplus.com/ref/
Spero di esserti utile, ciao.
Alessandro
abietre AT tiscalinet DOT it

}
Ok, io volevo evitare perň di dover inserire "ignore_comments", prima della
lettura
di ogni variabile.
Cioč, in alternativa all'approccio precedente, volevo implementare un
manipolatore che "chiamato"
una volta soltanto a un certo punto del programma,
alterasse permanentemente il comportamento dell' ifstream,
facendogli sistematicamente ignorare i commenti (se possibile).
Grazie
Stefano Zanobi


Quest'ultima soluzione è più elegante, ma più complessa da implementare,
anche se molto interessante.
Gli stream standard del c++ basano le loro operazione di input/output su
una gerarchia di classi derivate da std::streambuf (ad es. fstream utilizza
filebuf, derivata da streambuf).
Ogni streambuf utilizza un buffer di lettura, dal quale i metodi delle
classi stream attingono i dati.
Quando tale buffer è vuoto, viene invocato il metodo virtuale protetto
underflow, che provvede a
ricaricare il buffer (se possibile) o a segnalare la condizione di
errore/eof.
Il metodo setg ti permette di specificare la posizione dell'inizio, della
fine e la posizione di lettura
corrente nel buffer.
Potresti quindi creare una nuova classe derivata da streambuf, che utilizzi
uno streambuf esistente per
leggere i caratteri e che effettui le operazioni di filtraggio a te
necessarie. In tale classe dovresti
ridefinire essenzialmente il metodo underflow ed un metodo per
abilitare/disabilitare il filtraggio.
Una volta creato il tuo streambuf, lo puoi testare costruendo un oggetto di
classe std::istream,
passandogli come parametro nel costruttore un'istanza del tuo streambuf, al
quale si appoggerà
per le operazioni di i/o di basso livello.
Dovresti quindi creare una nuova classe derivata da istream, che basi le
proprie operazioni sullo
streambuf filtrante.
Tale classe dovrebbe a sua volta esporre un medo per abilitare/disabilitare
il filtraggio, che a sua
volta richiama il metodo corrispondente dello streambuf. Tale metodo
verrebbe quindi utilizzato
dal tuo manipolatore.
Con una soluzione del genere, dovresti essere in grado di applicare il
filtro a qualsiasi tipo
di stream, non solo agli fstream.
Per maggiori dettagli puoi consultare il link che ti ho postato ieri, oltre
ai sorgenti della libreria
(anche se non sono sempre chiarissimi), potresti provare a guardare come
funziona std::stringbuf.
Spero di essere stato sufficientemente chiaro, se hai ancora bisogno e non
hai particolarmente fretta,
chiedi ancora, ti risponderò appena possibile.
Ciao.


 chiedi ancora, ti risponderò appena possibile.
Grazie per la spiegazione molto esauriente, ora ho anche capito meglio un
paio di cosette sugli stream.
Certo è un po' più complesso di quello
che mi aspettavo, almeno per l'utilizzo che mi prefiggevo di farne...
Continuo a provare col primo metodo.
Stefano Zanobi

 Come faccio? :)
chiama direttamente l'operatore globale:
    return ::operator >> (*this, c);
              ^^
[...]
PS: ho notato che stiamo portando avanti il dialogo su due ng, se possibile
continuiamo su it.comp.lang.c++


               ^^
Ok, ora funziona perfettamente!
Ti ringrazio di nuovo per tutte le spiegazioni e le dritte su come
"personalizzare" streambuf, sei stato molto gentile.
Ciao,
Stefano Zanobi