11

I've used statements such as this quite a bit in my C++ programming:

std::string s;
std::ifstream in("my_input.txt");
if(!in) {
    std::cerr << "File not opened" << std::endl;
    exit(1);
}
while(in >> s) {
    // Do something with s
}

What I want to know is, why does this work?

I looked at the return value of operator>>, and it's an istream object, not a boolean. How does an istream object somehow get interpreted as a bool value that can be put inside of if statements and while loops?

bobroxsox
  • 902
  • 2
  • 10
  • 26
  • 1
    It does not have to *be* a `bool` it just needs to have an *implicit conversion* to `bool`. For example, any of the following are "falsy": `0`, `nullptr`, `0x0`, `false`, etc. – Cory Kramer Feb 13 '15 at 17:29
  • Hmm I see. How can you tell which classes have an implicit conversion to bool? – bobroxsox Feb 13 '15 at 17:31
  • 1
    As @JosephMansfield mentioned, the class must have `operator bool()` defined. – Cory Kramer Feb 13 '15 at 17:32
  • 1
    @bobroxsox By reading the documentation of the class. If a class is meant to be used as a boolean, then this fact will be clearly documented. (For various historical reasons, the conversion to "bool" may be an `operator void*`, or even a conversion operator to some unknown pointer type, rather than an `operator bool`.) – James Kanze Feb 13 '15 at 18:34

3 Answers3

10

The base class std::basic_ios provides an operator bool() method that returns a boolean representing the validity of the stream. For example, if a read reached the end of file without grabbing any characters, then std::ios_base::failbit will be set in the stream. Then operator bool() will be invoked, returning !fail(), at which time extraction will stop because the condition is false.

A conditional expression represents an explicit boolean conversion, so this:

while (in >> s)

is equivalent to this

while (static_cast<bool>(in >> s))

which is equivalent to this

while ((in >> s).operator bool())

which is equivalent to

while (!(in >> s).fail())
David G
  • 94,763
  • 41
  • 167
  • 253
  • 3
    Of course, in pre-C++11, it wasn't `operator bool`, but `operator void*`. But the effect was the same, since `void*` converts implicitly to `bool`. – James Kanze Feb 13 '15 at 18:35
5

std::basic_ios, from which the input and output streams inherit, has the conversion function operator bool (or operator void* prior to C++11 to get around the safe-bool problem, which is no longer an issue thanks to the explicit keyword).

Joseph Mansfield
  • 108,238
  • 20
  • 242
  • 324
3

See std::basic_ios::operator bool:

This operator makes it possible to use streams and functions that return references to streams as loop conditions, resulting in the idiomatic C++ input loops such as while(stream >> value) {...} or while(getline(stream, string)){...}. Such loops execute the loop's body only if the input operation succeeded.

Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271