Newsgroup: it.comp.lang.c++
Titolo: Problemino con la STL

Salve a tutti
In questo programma volevo semplicemente leggere un file per metterlo in una
stringa.
#include <fstream>
#include <string>
#include <iterator>
void leggiFile(std::string &str, const char *fileName)
{
    std::ifstream inputFile(fileName);
    std::string fileData((std::istreambuf_iterator<char>(inputFile)),
    std::istreambuf_iterator<char>());
    str = fileData;
}
int main()
{
    std::string strFile;
    leggiFile(strFile, "Myfile.txt");
    return 0;
}
Sto compilando col MsVisualC++ 6 e mi da i seguenti errori:
c:\test\prova\prova.cpp(337) : error C2061: syntax error : identifier
'inputFile'
c:\test\prova\prova.cpp(337) : error C2066: cast to function type is illegal
c:\test\prova\prova.cpp(337) : error C2059: syntax error : ','
c:\test\prova\prova.cpp(339) : error C2065: 'fileData' : undeclared
identifier
Ho anche provato con il DevC++ ultima versione beta, ma qua addirittura non
sa chi sia istreambuf_iterator e anche cambiandolo con istream_iterator vi
sono altri problemi di matching:
C:/Dev-C++/include/g++-3/std/bastring.h:439: no match for
`istream_iterator<char,int> & - istream_iterator<char,int> &'
make.exe: *** ["TestTemplateMain.o"] Error 1
 0
Maurus

Ho parzialmente cambiato cosi' come dice Meyers nel suo "Effective STL"
ma ancora problemi....
#include <iostream>
#include <fstream>
#include <string>
#include <iterator>
void leggiFile(std::string &str, const std::string &fileName)
{
 std::ifstream inputFile(fileName.c_str());
 std::istreambuf_iterator<char> dataBegin(inputFile);
 std::istreambuf_iterator<char> dataEnd;
 std::string fileData(dataBegin,
  dataEnd);
 str = fileData;
}
int main()
{
 std::string strFile;
 std::string fileName("Myfile.txt");
 leggiFile(strFile, fileName);
 std::cout << strFile << std::endl;
 system("PAUSE");
 return 0;
}
c:\test\prova\prova.cpp(350) : error C2664: '__thiscall
std::basic_string<char,struct std::char_traits<char>,class
std::allocator<char> >::std::basic_string<char,struct
std::char_traits<char>,class std::allocator<char> >(const char *,unsigned
int,co
nst class std::allocator<char> &)' : cannot convert parameter 1 from 'class
std::istreambuf_iterator<char,struct std::char_traits<char> >' to 'const
char *'
        No user-defined-conversion operator available that can perform this
conversion, or the operator cannot be called
Error executing cl.exe.
Baco del compilatore?
Maurus

 }
Qualche appunto.  Per cominciare, non controlli se l'apertura del file
e' andata a buon fine.  Inoltre, leggi in una string che poi viene
copiata su un'altra; perche'?  Non conviene leggere nella string
finale direttamente?  Poi: la string viene creata vuota e, se il file
e' di una certa dimensione, verra' espansa (e quindi riallocata) piu'
volte, con conseguente perdita di tempo; non conviene settarla
opportunamente fin dall'inizio?  Infine (last but not least); la
maniera di riempire la string non mi piace :-)
Io farei cosi' (non testato, chissa' quanti errori ;-)
std::ifstream inputFile(fileName);
if (inputFile) {
  inputFile.seekg(0, std::ios::end);
  std::ifstream::pos_type p = inputFile.tellg();
  std::cout << "Il mio file e' lungo " << p << " bytes" << std::endl;
  inputFile.seekg(0);           // Mi riposiziono all'inizio
  str.reserve(p);               //   e chiedo abbastanza spazio
                                //     nella mia string
  std::copy(std::istreambuf_iterator<char>(inputFile),
            std::istreambuf_iterator<char>(),
            std::back_inserter(str));
  inputFile.close();            // E' buona educazione chiudere quello
                                //   che si e' aperto
  std::cout << "Il file contiene: =====>" << str << "<=====\n";
} else {
  std::cerr << "Aiuto!  Non riesco ad aprire " << fileName << std::endl;
}
-- 
Maurizio Loreti                         
http://www.pd.infn.it/~loreti/mlo.html
Dept. of Physics, Univ. of Padova, Italy          loreti at pd dot infn dot it

 Maurizio Loreti
Ciao Maurizio,
ti ringrazio per i suggerimenti ma....
il mio post nasceva dal fatto che volevo implementare la funzione leggiFile
alla maniera in cui lo spiega Scott Meyers nel suo "Effective STL".
So che ci possono essere 1000 altri modi per farlo, ma volevo capire questo
modo in quanto "in teoria", farebbe cio' in 2 o 3 righe di codice:
     std::ifstream inputFile(fileName);
     std::string fileData((std::istreambuf_iterator<char>(inputFile)),
         std::istreambuf_iterator<char>());
E' vero che non ho fatto il controllo degli errori nell'apertura file, ma il
fatto che poi copio la stringa che ho riempito col file fileData sulla
stringa che ho passato come parametro, perche' qui fileData fa tutto col
costruttore.
Cioe' la costruzione di fileData e' fatta mediante l'uso di
istreambuf_iterator, mentre la str che ho passato alla funzione leggiFile e'
gia' stata costruita e non saprei come assegnargli direttamente il risultato
di cio' che viene qui fatto col costruttore.
Resta comunque il fatto che non ho ancora capito perche' l'implementazione
di cio' non funzioni, anche cambiandola come ho fatto nell'altro mio post.
Misteri delle implementazioni STL fatte dai vari compilatori.
Maurus

 wrote in message
news:a9om1u$51crn$1...@ID-125555.news.dfncis.de...


 a écrit dans le message news:
8ad6wwt...@mlinux.pd.infn.it...
No Maurizio,
nonostante abbia provato la tua versione sul MsVisualC++ 6 e sul DevC++ ho
ancora problemi in compilazione.
Ecco come ho aggiustato il tuo programma coi vari include e con il main
#include <iostream>
#include <fstream>
#include <iterator>
#include <string>
void leggiFile(std::string &str, const std::string &fileName)
{
    std::ifstream inputFile(fileName.c_str());
    if (inputFile)
    {
         inputFile.seekg(0, std::ios::end);
        std::ifstream::pos_type p = inputFile.tellg();
        std::cout << "Il mio file e' lungo " << p << " bytes" << std::endl;
        inputFile.seekg(0);         //   Mi riposiziono all'inizio
        str.reserve(p);                //   e chiedo abbastanza spazio
                                             //   nella mia string
        std::copy(std::istreambuf_iterator<char>(inputFile),
        std::istreambuf_iterator<char>(),
        std::back_inserter(str));
        inputFile.close();            // E' buona educazione chiudere quello
                                             //   che si e' aperto
        std::cout << "Il file contiene: =====>" << str << "<=====\n";
        }
        else
        {
            std::cerr << "Aiuto!  Non riesco ad aprire " << fileName <<
std::endl;
        }
}
int main()
{
    std::string strFile;
    std::string fileName("Myfile.txt");
    leggiFile(strFile, fileName);
    std::cout << strFile << std::endl;
#ifdef WIN32
 system("PAUSE");
#endif
    return 0;
}
e l'errore e':
c:\program files\microsoft visual studio\vc98\include\iterator(82) : error
C2039: 'push_back' : is not a member of 'basic_string<char,struct
std::char_traits<char>,class std::allocator<char> >'
        c:\program files\microsoft visual studio\vc98\include\iterator(82) :
while compiling class-template member function 'class
std::back_insert_iterator<class std::basic_string<char,struct
std::char_traits<char>,class std::allocator<char> > > &_
_thiscall std::back_insert_iterator<class std::basic_string<char,struct
std::char_traits<char>,class std::allocator<char> > >::operator =(const char
&)'
Maurus

 c:\test\prova\prova.cpp(337) : error C2066: cast to function type is illegal
Innazitutto ci sono delle parentesi di troppo attorno al primo argomento.
 
Anche togliendo quelle parentesi, perņ, non credo che compilerą. Il
compilatore cercherą di interpretare fileData come la dichiarazione di una
funzione che restituisce un std::string e che accetta come primo argomento
un std::istreambuf_iterator<char>.
Prova a sostituire i due temporanei con delle variabili.
   std::istreambuf_iterator<char> beg( inputFile );
   std::istreambuf_iterator<char> end;
   std::string fileData( beg, end );
Max

 alla maniera in cui lo spiega Scott Meyers nel suo "Effective STL".
Il tuo esempio compila ed esegue bene sotto Linux con g++ 3.0.4 e
sotto Solaris con KCC 4.0f.  Ho guardato la string col debugger e
contiene l'intero file.  E' un difetto del tuo compilatore...



Ciao Max,
quelle parentesi di troppo le ho copiate da un esempio del libro "Effective
STL" di Scott Meyers, e penso che le abbia messe appositamente per qualche
specie di conversione che ancora non ho capito.
Fatto sta che con la tua modifica, MSVisualC++ 6 mi da ancora un errore
sulla linea:
     std::string fileData(beg, end);
e il messaggio e' questo
 c:\test\prova\prova.cpp(345) : error C2664: '__thiscall
std::basic_string<char,struct std::char_traits<char>,class
std::allocator<char> >::std::basic_string<char,struct
std::char_traits<char>,class std::allocator<char> >(const char *,unsigned
int,co
nst class std::allocator<char> &)' : cannot convert parameter 1 from 'class
std::istreambuf_iterator<char,struct std::char_traits<char> >' to 'const
char *'
        No user-defined-conversion operator available that can perform this
conversion, or the operator cannot be called
I files che ho incluso sono i seguenti:
#include <iostream>
#include <fstream>
#include <string>
#include <iterator>
Non capisco perche' il compilatore si lamenta per il fatto di aver
convertito il parametro 1 a const char *.
Per me e' il VisualC++ 6 ad avere problemi, ma ne ho altri quando compilo
questo stesso programma con DevC++.
Maurus

 Maurizio Loreti
http://www.pd.infn.it/~loreti/mlo.html
Come sospettavo...
mi sembrava strano che Scott Meyers "cannasse" cosi' facilmente.
Insomma non ho ancora un programma valido che faccia quello che ho chiesto
(mettere un file in una stringa), che compili e linki col VisualC++
6....incredibile.
Bisognera' convertirsi al linux?
Maurus

 Bisognera' convertirsi al linux?
Noi abbiamo 'installato' la STL sgi sotto VC++6... č stato 
leggerissimamente piů rapido e produttivo... ;)
 
-- 
Luc.

 conversion, or the operator cannot be called
Se non ricordo male MSVC6 non supporta le funzioni membro template e
perciň non si puň contare sul costruttore template previsto da
std::string:
  template <class InIt>
        basic_string(InIt first, InIt last);
Max

"Luc" <XXX...@katamail.comXXX> a écrit dans le message news:
MPG.172a3af52...@tornado.fastwebnet.it...

Se e' free, lo faro' anche io.
C'e' anche la Dinkumware ma e' a pagamento mi sembra.
Maurus


Hai ragione non ricordi male.
Cosi' funziona, in parte grazie a te , in parte a Loreti e in grossa parte
grazie a un americano che mi ha dato la dritta giusta:
   std::istreambuf_iterator<char> beg( inputFile );
   std::istreambuf_iterator<char> end;
   std::copy(beg,end,std::inserter(str,str.end()));
Certo che per far funzionare le cose come standard comanda sotto MsVisualC++
6 ce ne vuole!
Maurus

un std::istreambuf_iterator<char>.
Quell'esempio e' proprio relativo al problema che a volte
le regole di parsing del C++ possono essere sorprendenti
(item 6: "be alert for C++'s most vexing parse").
Le parentesi sono aggiunte proprio per eliminare la
possibile interpretazione come dichiarazione (e nel
libro si dice anche che non con tutti i compilatori questo
e' sufficiente a ottenere una corretta interpretazione).
Andrea

 argomento.
no, le parentesi ci vogliono eccome: senza di quelle il compilatore 
interpreta la riga come la dichiarazione di una funzione chiamata 
fileData, ma grazie alle parentesi non c'e` piu` ambiguita` e la linea 
puo` essere interpretata solo come una definizione.
Scott Meyers, nell'item 6 di Effective STL presenta proprio questo 
esempio.
ciao Anto
-- 
Antonio Cuni, 19 anni, studente
Brainbench C++ Master: 4.73, higher than 99% of all previous test takers.
C Language: 3.79, higher than 92% of all previous test takers.
Guida C/C++ di Programmazione.it: 
http://cpp.programmazione.it

 Sto compilando col MsVisualC++ 6 e mi da i seguenti errori:
il tuo codice e` corretto, ma devi ammettere che mette a dura prova la 
capacita` di parsing dei compilatori ;-)
cmq con gcc 3.0.4 compila alla perfezione; come work-around per VC++ 
puoi fare come ti e` gia` stato suggerito: definire due variabili di 
appoggio.


            std::back_inserter(str));
Purtroppo con il VC++ non c'é nulla da fare neanche in questo
modo,pare che la gestione degli istream_iterator con questo
compilatore sia altrettanto bacata.
Il Ghenio
---------
// TODO: Place your ass here

 a écrit dans le message news:
OGTBPL+adn3pDY...@4ax.com...

Ciao,
grazie a un americano ho risolto cosi':
   std::istreambuf_iterator<char> beg( inputFile );
   std::istreambuf_iterator<char> end;
   std::copy(beg,end,std::inserter(str,str.end()));
Maurus

    std::ifstream inputFile(fileName);
[CUT]
Orbene, posso dirti con certezza assoluta che il codice é corretto e
dovrebbe compilare con un compilatore sufficiente standard. Il VC++6.0
ha dei problemi evidenti sulla gestione degli istream_iterator, ma io
ti propongo una versione più chiara, più sicura  e sicuramente più
performante di quella che hai riportato,che si incarica anche di
controllare la corretta apertura del file.
Scusami se ho modificato i nomi delle variabili, ma sono dell'opinione
che le variabili con nomi mezzo maiuscolo e mezzo minuscolo possano
spesso portare a creare confusione( ci si dimentica spesso quali
lettere sono minuscole e quali maiuscole) ed a fare perdere tempo
complicando inutilmente la vita in un linguaggio già sufficientemente
complicato. Personalmente consiglio di usare sempre lettere minuscole,
con le quali mi ci ritrovo molto bene.
Versione provata con successo su Borland c++ 5.5, compilatore più
standard del VC++
#include <fstream>
#include <string>
#include <iterator>
#include <algorithm>
bool leggifile(const char *fname,std::string &strres)
{
strres="";
std::ifstream inputfile(fname,std::ios_base::end);
if(inputfile)
    {
    //riservo alla stringa una quantità di memoria pari alla lunghezza
    //del file,questo fa si che non si debba riallocare memoria per la
    //stringa, con evidente incremento di prestazioni nel caso che il
    //file sia particolarmento grosso.
    strres.reserve(inputfile.tellg());
    inputfile.seekg(0);
    std::istreambuf_iterator<char> fbeg(inputfile);
    std::istreambuf_iterator<char> eos;
    std::copy(fbeg,eos,std::back_inserter(strres));
    inputfile.close();
    return true;
    }
else
    {
    /*fallimento apertura file*/
    return false;
    }
}
int main()
{
std::string strfile;
if(leggifile("Myfile.txt",strfile))
    {
    //famoce n'bel test...
    std::cout<<strfile;
    }
return 0;


 Bisognera' convertirsi al linux?
No, gcc 3.0.4 è disponibile anche per Windows; possibilità:
Io uso DJGPP, 
www.djdelorie.com/djgpp
 che è un port di DJGPP per DOS(non per
Windows, quindi niente DLL né finestre), con RHIDE come editor(molto, molto
meglio di Dev-C++, col debugger integrato!)
Oppure, Dev-C++ può usare un compilatore mingw o Cygwin (altri due port di
gcc, tutti e due per Windows) esterno(tra i readme c'è scritto come fare),
da scaricare dai rispettivi siti(che purtroppo non so quali siano, ma che
forse sono linkati da 
http://gcc.gnu.org
 .