8

My question is how does,

while(cin>>x)
{
     //code
}

work. Or to be more specific, what about that code halts the loop?

From the documentation here, it looks like the >> operator returns a &istream. Does that mean if the read fails or hits the end of file it not only sets the eofbit, failbit or badbit but also returns a null? That doesn't really make sense so I doubt that's it.

Is there some kind of implicit check of the eofbit?

I ask because I'm hoping to implement something similar with 2 classes like this,

class B
{
   //variables and methods
}

class A
{
   //Variables and methods
   //Container of B objects. ex. B[] or vector<B> or Map<key,B>
   &A >> (B b);
}

int main()
{
   A a;
   B b;

   while( a >> b)
   {
      //Code
   }

}

Note: I'm not looking to inherit from istream unless it's where the magic that makes this work come from. The reason for this is I'm hoping to keep the classes and their dependencies as small as possible. If I inherit from istream I will receive all its public and protected stuff and I'm not trying to create an istream like object. I just want to copy one REALLY nice piece of it.

Edit: I'm using Visual Studio 2010, (which is becoming a real pain) and I'm going to need something compatible with it's implementation of C++03 + some C++11.

Dan
  • 2,625
  • 7
  • 39
  • 52
  • 8
    [15.4 How does that funky while (std::cin >> foo) syntax work?](http://www.parashift.com/c++-faq/istream-and-while.html). Note that in C++11, it has an explicit bool conversion instead. – chris Oct 16 '12 at 21:34
  • 1
    @chris Prefect. Now could you write up an example of how I can do that with the above stuff and get +15? – Dan Oct 16 '12 at 21:39
  • What would `while( a >> b)` do? I don't understand the example. – Jesse Good Oct 16 '12 at 21:39
  • Might have missed my edit. a has a container of B objects or in my case a pointer to the head of a linked list which the >> operator will traverse to the end. – Dan Oct 16 '12 at 21:43

2 Answers2

6

From the documentation here, it looks like the >> operator returns a &istream. Does that mean if the read fails or hits the end of file it not only sets the eofbit, failbit or badbit but also returns a null?

No, a reference to the stream object is returned, but the internal flags will be set. Subsequent calls to operator>> will fail after just testing those flags.

Is there some kind of implicit check of the eofbit?

Not sure what the question is. The stream will not try to find upfront whether the next request will fail, but only set the flag if one operation failed because it hit EOF. Each call to operator>> will first test the state of the stream, and will only proceed if the stream is in a good condition.

How does while(cin>>x) work?

There is an implicit conversion from the stream object to a boolean. The conversion yields true if the stream is in a good condition or false otherwise.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • If I'm reading the document @chris linked to correctly the `>>` operator does return a null if it fails. But because its in a `bool` context it is then converted to a `void*` by the `()` operator which is interpreted as 0 causing the loop to halt. Alternatively if it returned a reference to itself, when converted to a `void*` by `()` it would be non-0 allowing the loop to continue. And because the `()` conversion doesn't happen till the expression is evaluated to be in a `bool` syntax you can nest `>>` like, `while(cin >>x>>y>>z)` and it will not convert to a `void*` till `>> z` is processed. – Dan Oct 16 '12 at 22:25
  • @Dan: The signature is `istream& operator<<...` there is no such thing as a null reference in the language. The returned object is a reference to the `istream&`, and the conversion to bool is done through a conversion to `void*` (which seemed appropriate when the library was designed, but is not the best approach: the safe-bool idiom would be a better choice for a number of reasons). The conversion is implemented as a member function inside the `istream` class, and it yields either a non-null pointer if the `istream` is in a good state or NULL if it is not. – David Rodríguez - dribeas Oct 16 '12 at 23:15
  • ... you are right that the conversion is only triggered when needed, but I fear you are confusing what is otherwise quite simple: `operator>>` returns `*this` (always), you define a conversion operator that allows implicit conversion to `bool` (in the safe-bool idiom is a pointer-to-member, in `istream` it is a `void*`). The rest falls into place on itself. – David Rodríguez - dribeas Oct 16 '12 at 23:17
  • You're right I was confused on the way that the `void*` value was being determined. After reading the documentation more closely I understand what was really happening. But I have one small issue. According to the [this](http://www.cplusplus.com/reference/iostream/ios/operator_voidpt/) The `eofbit` doesn't translate to a NULL pointer. How does the loop end at the EOF then? Or is this a mistake in the documentation? – Dan Oct 16 '12 at 23:50
  • 1
    @Dan: If the extraction operator fails to extract any data (or the data is not interpretable as the target type) the `istream` *failbit* (or *badbit*) will be set. This means that for a file that contains a single character the first `in >> ch` (assuming `ch` of type char) will read the character, the second `in >> ch` will fail to read and set *failbit* so `in` conversion to `void*` will yield null and that will be converted to `false`. Depending on what you *read*, *eof* can be set when reading the last valid element or when trying to read the next, *failbit* will be set on the next read. – David Rodríguez - dribeas Oct 17 '12 at 01:37
5

Now could you write up an example of how I can do that with the above stuff?

Like this:

// UNTESTED
class B
{
   //variables and methods
}

class A
{
   bool still_good;

   //Variables and methods
   //Container of B objects. ex. B[] or vector<B> or Map<key,B>
   A& operator>>(B& b) {
     try_to_fill_b();
     if(fail) still_good = false;
     return *this;
   }
   explicit operator bool() { return still_good; }
}

int main()
{
   A a;
   B b;

   while( a >> b)
   {
      //Code
   }

}
Robᵩ
  • 163,533
  • 20
  • 239
  • 308
  • Noting, of course, that this code is C++11-only, and that one should use the safe-bool idiom for C++03 rather than an implicit `operator bool()`. (Also, your operator should be `const`.) – ildjarn Oct 16 '12 at 21:46
  • @ildjarn great point. I'm using VS2010 is this going to work in that version of c++? – Dan Oct 16 '12 at 21:50
  • @Dan : No, explicit operators are not yet supported in VC++. – ildjarn Oct 16 '12 at 21:51
  • Rob can you take a stab at this in an edit with VC++ in mind? – Dan Oct 16 '12 at 21:53
  • @Dan : As I said in my first comment, one should __not__ implement an implicit operator, but should implement the safe-bool idiom instead. – ildjarn Oct 17 '12 at 18:40
  • That comment was only meaningful if I knew from the start what the safe-bool idiom was. I had to look it up first, which is how I came to the conclusion of dropping the `explicit`. Looking back at the original question I was basically asking what the safe-bool idiom was without knowing it existed. – Dan Oct 17 '12 at 19:21
  • @Dan : Fair enough, but now that you know the name, searching SO/the web for idiomatic implementations should be trivial, which was the entire point. ;-] One shouldn't expect detailed comments as they do detailed answers; oftentimes a simple comment telling you what to look for is more than sufficient. – ildjarn Oct 17 '12 at 19:54