eold
eold

Reputation: 6042

C++: std::istream check for EOF without reading / consuming tokens / using operator>>

I would like to test if a std::istream has reached the end without reading from it.

I know that I can check for EOF like this:

if (is >> something) 

but this has a series of problems. Imagine there are many, possibly virtual, methods/functions which expect std::istream& passed as an argument. This would mean I have to do the "housework" of checking for EOF in each of them, possibly with different type of something variable, or create some weird wrapper which would handle the scenario of calling the input methods.

All I need to do is:

if (!IsEof(is)) Input(is);

the method IsEof should guarantee that the stream is not changed for reading, so that the above line is equivalent to:

Input(is)

as regards the data read in the Input method.

If there is no generic solution which would word for and std::istream, is there any way to do this for std::ifstream or cin?

EDIT: In other words, the following assert should always pass:

while (!IsEof(is)) {
  int something;
  assert(is >> something);
}

Upvotes: 6

Views: 5571

Answers (5)

Ephphatha
Ephphatha

Reputation: 596

The istream class has an eof bit that can be checked by using the is.eof() member.

Edit: So you want to see if the next character is the EOF marker without removing it from the stream? if (is.peek() == EOF) is probably what you want then. See the documentation for istream::peek

Upvotes: 8

Logan Capaldo
Logan Capaldo

Reputation: 40336

That's impossible. How is the IsEof function supposed to know that the next item you intend to read is an int?

Should the following also not trigger any asserts?

 while(!IsEof(in))
 {
    int x;
    double y;
    if( rand() % 2 == 0 )
    {
       assert(in >> x);
    } else {
       assert(in >> y);
    }
 }

That said, you can use the exceptions method to keep the "house-keeping' in one place.

Instead of

   if(IsEof(is)) Input(is)

try

   is.exceptions( ifstream::eofbit /* | ifstream::failbit etc. if you like */ )
   try {
     Input(is);
   } catch(const ifstream::failure& ) {
   }

It doesn't stop you from reading before it's "too late", but it does obviate the need to have if(is >> x) if(is >> y) etc. in all the functions.

Upvotes: 5

Bo Persson
Bo Persson

Reputation: 92261

No, in the general case there is no way of knowing if the next read operation will reach eof.

If the stream is connected to a keyboard, the EOF condition is that I will type Ctrl+Z/Ctrl+D at the next prompt. How would IsEof(is) detect that?

Upvotes: 0

AProgrammer
AProgrammer

Reputation: 52284

There are good reasons for which there is no isEof function: it is hard to specify in an usable way. For instance, operator>> usually begin by skipping white spaces (depending on a flag) while some other input functions are able to read space. How would you isEof() handle the situation? Begin by skipping spaces or not? Would it depend on the flag used by operator>> or not? Would it restore the white spaces in the stream or not?

My advice is use the standard idiom and characterize input failure instead of trying to predict only one cause of them: you'd still need to characterize and handle the others.

Upvotes: 0

sehe
sehe

Reputation: 392931

Normally,

if (std::is)
{ 
}

is enough. There is also .good(), .bad(), .fail() for more exact information

Here is a reference link: http://www.cplusplus.com/reference/iostream/istream/

Upvotes: 0

Related Questions