/ Forside / Teknologi / Udvikling / C/C++ / Nyhedsindlæg
Login
Glemt dit kodeord?
Brugernavn

Kodeord


Reklame
Top 10 brugere
C/C++
#NavnPoint
BertelBra.. 2425
pmbruun 695
Master_of.. 501
jdjespers.. 500
kyllekylle 500
Bech_bb 500
scootergr.. 300
gibson 300
molokyle 287
10  strarup 270
At læse en int fra stream.
Fra : Bertel Brander


Dato : 06-02-05 20:57

Hej gruppe,

Jeg tænkte at jeg ville lave en lille template funktion til
at læse et tal fra en stream. Formålet er at checke om
man kunne læse og konvertere denne, samt at sikre at der ikke
står noget og hænger i stream'en efter brug. Funktionen
er mest tænkt til at læse fra keyboard.

Det blev til dette:

template <typename T>
bool Get(T &t, std::istream &is = std::cin, std::string *Rest = 0)
{
std::string s;
std::getline(is, s);
std::stringstream ss(s);
if(ss >> t)
{
if(ss.peek() == std::istream::traits_type::eof() ||
ss.peek() == 0)
return true;
if(Rest)
std::getline(ss, *Rest);
}
return false;
}

Delen efter if(ss >> t) skulle checke om der står noget i bufferen
efter man har konverteret; hvis brugeren bliver bedt om at læse
en int og skriver 123pop, vil konverteringen gå godt (ss >> t) er true,
men jeg vil gerne finde ud af at der er skrevet pop efter tallet og
læse dette over i Rest (hvis den ikke er 0).

Problemet er at jeg ikke mener at det burde være nødvendigt at bruge
ss.peek() == 0, men Borland C++ returnerer 0 ved peek, selvom der ikke
står noget i bufferen og std::istream::traits_type::eof() er -1.

Er det noget jeg må lære at leve med, eller er der en bedre måde
at checke på?

Er der andre problemer med funktionen?

Jeg burde måske bruge eq_int_type til at checke ss.peek() værdien,
men jeg kan ikke regne ud hvad den funktion gør.

På forhånd tak.

--
Absolutely not the best homepage on the net:
http://home20.inet.tele.dk/midgaard
But it's mine - Bertel

 
 
Mogens Hansen (07-02-2005)
Kommentar
Fra : Mogens Hansen


Dato : 07-02-05 18:54


"Bertel Brander" <bertel@post4.tele.dk> wrote in message
news:4206766d$0$12776$edfadb0f@dread14.news.tele.dk...

[8<8<8<]
> if(ss.peek() == std::istream::traits_type::eof() ||
> ss.peek() == 0)

Brug
if(ss.eof())

Det siger mere direkte hvad du ønsker (og det virker både med Borland
C++Builder V6 og Microsoft Visual C++.NET 2003).

Der er i øvrigt en fejl i basic_stringbuf<...>::ssekoff(...) i den STLPort
version der følger med Borland C++Builder V6.
Den havde nummer 623 på STLPort forum - men jeg kan ikke finde den længere.
Jeg ved ikke om det spiller en rolle for det du har observeret.
Hvis du har behov for yderlige information om dette problem, så sig til -
jeg har både test case og løsning.

[8<8<8<]
> Er der andre problemer med funktionen?

Hvis indlæsningen af "t" fejler går resten af linien tabt, uanset hvad der
måtte stå.
Er det hensigten ?

Staten af "is" bliver ikke sat som følge af en fejl ved læsning (fail bit).
Det er lidt atypisk.
Er det hensigten ?

Måske er det en ide at overloade funktionen til at tage en reference til en
string "rest", for at kunne kalde den uden at tage adressen af en variable:

istringstream is("123");
string rest;
int i;

get(i, is, rest);

altså

template <typename T>
bool get(T &t, istream& is = cin, string* rest = 0)
{
string s;
getline(is, s);
istringstream ss(s);
if(ss >> t) {
if(ss.eof())
return true;
if(rest)
getline(ss, *rest);
}
return false;
}

template <typename T>
inline bool get(T& t, istream& is, string& rest)
{
return get<T>(t, is, &rest);
}

Venlig hilsen

Mogens Hansen



Bertel Brander (07-02-2005)
Kommentar
Fra : Bertel Brander


Dato : 07-02-05 19:50

Mogens Hansen wrote:
> "Bertel Brander" <bertel@post4.tele.dk> wrote in message
> news:4206766d$0$12776$edfadb0f@dread14.news.tele.dk...
>
> [8<8<8<]
>
>> if(ss.peek() == std::istream::traits_type::eof() ||
>> ss.peek() == 0)
>
>
> Brug
> if(ss.eof())

Simpelt, og det virker, tak.

>
>
> Hvis indlæsningen af "t" fejler går resten af linien tabt, uanset hvad der
> måtte stå.
> Er det hensigten ?

Ja.

>
> Staten af "is" bliver ikke sat som følge af en fejl ved læsning (fail bit).
> Det er lidt atypisk.
> Er det hensigten ?

Ja, det er meningen at man skal checke returværdien af Get og
ellers være klar til at læse igen.

>
> Måske er det en ide at overloade funktionen til at tage en reference til en
> string "rest", for at kunne kalde den uden at tage adressen af en variable:

Ja, og nej. Det ville måske være pænere, men resultatet er at begge
disse er ok:

int n;
std::string s;
Get(n, std::cin, s);
Get(n, std::cin, &s);

Og det er jeg ikke sikker på er smart.

Så hellere lave disse to:
template <typename T>
bool Get(T &t, std::istream &is = std::cin)

template <typename T>
bool Get(T &t, std::string &Rest, std::istream &is = std::cin)

--
Absolutely not the best homepage on the net:
http://home20.inet.tele.dk/midgaard
But it's mine - Bertel

Bertel Brander (08-02-2005)
Kommentar
Fra : Bertel Brander


Dato : 08-02-05 22:49

Bertel Brander wrote:
>>
>> Brug
>> if(ss.eof())
>
>
> Simpelt, og det virker, tak.

Øv, der glædede jeg mig for tidligt, det virker ikke!

Pt har jeg følgende Get funktion:

template <typename T>
bool Get(T &t, std::istream &is = std::cin, std::string *Rest = 0)
{
std::string s;
std::getline(is, s);
std::stringstream ss(s);
if(ss >> t)
{
if(ss.eof())
return true;
if(Rest)
std::getline(ss, *Rest);
}
return false;
}

Og et lille test program:
int main()
{
int n;
std::cout << "Enter First Number: ";
Get(n);

int m;
do
{
std::cout << "Enter second number: ";
}
while(!Get(m));
std::cout << n << " + " << m << " = " << (n + m) << std::endl;
}

Borland (Borland C++ 5.5) returnerer altid false.
Visual C++ 6.0 opfører sig sært, den skal have to gange
enter inden den accepterer første input.
Det virker med g++ (mingw 3.3.1) og Digital Mars.

Nogen gode forslag (udover at skrotte Borland og Visual) ?

Jeg overvejede at lave en løsning med strtol/strtod men
så er jeg vel nødt til at have to (eller flere) funktioner?

--
Absolutely not the best homepage on the net:
http://home20.inet.tele.dk/midgaard
But it's mine - Bertel

Søg
Reklame
Statistik
Spørgsmål : 177455
Tips : 31962
Nyheder : 719565
Indlæg : 6408147
Brugere : 218880

Månedens bedste
Årets bedste
Sidste års bedste