Why Istream Object Can Be Used as a Bool Expression

Why istream object can be used as a bool expression?

The exact mechanism that enables use of an istream as a boolean expression, was changed in C++11. Previously is was an implicit conversion to void*, as you've found. In C++11 it is instead an explicit conversion to bool.

Use of an istream or ostream in a boolean expression was enabled so that C++ programmers could continue to use an expression with side-effects as the condition of a while or for loop:

SomeType v;

while( stream >> v )
{
// ...
}

And the reason that programmers do that and want that, is that it gives more concise code, code that is easier to take in at a glance, than e.g. …

for( ;; )
{
SomeType v;

stream >> v;
if( stream.fail() )
{
break;
}
// ...
}

However, in some cases even such a verbose structure can be preferable. It depends.

Why doesn't this comparison to bool work for an istream?

Because the implicit conversion operator of cin is

operator void*() const { ... }

and it can evaluate to zero, so you can check it against zero

while (cin >> x) {}

Conversion operator for bool declared as explicit so your expression will not invoke it:

explicit operator bool(){ ... }

So, you need an explicit cast:

if (true == static_cast<bool>(cin >> a))
{
}

Why do while(std::getline) loops work even though std::getline doesn't return a bool?

std::getline inherits std::basic_istream, that inherits std::basic_ios, that implements std::basic_ios<CharT,Traits>::operator bool.

while requires a bool resulting expression, thus

while(std::getline(iss, temp, ' ')) {
...
}

is attempted by the compiler under the hood like as

while(static_cast<bool>(std::getline(iss, temp, ' '))) {
...
}

and conversion is performed successfully as

while(std::getline(iss, temp, ' ').operator bool()) {
...
}

How is std::getline() equated with bool?


Does std::ifstream implement an operator bool()?

It does:

Checks whether the stream has no errors. <...> Returns true if the stream has no errors and is ready for
I/O operations. Specifically, returns !fail().

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)){...}

Why does while(std::ifstream s) work?

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())

Implicit conversion of stream to bool

std::ifstream's inherited operator bool is marked explicit:

explicit operator bool() const;
(2) (since C++11)

What this means is that there is no implicit conversion to bool, i.e. all of those expressions fail:

bool result = is;    // fails
bool b = is == true; // fails
if (is == false); // fails
while (is == false); // fails

If you wonder why if (is) and similar statements compile, that is because there are special rules for if, while, and the like for conversions: The explicit keyword is ignored!

if (is);                        // ok
while (is) // ok
bool b = static_cast<bool>(is); // ok

Note that the last case compiles because you are explicitly wanting a bool.

Technically, !is would work fine, as you explicitly want a bool, but std::ifstream has a inherited operator!, so that operator is called instead of the default operator! which operates on bools:

if (!is);     // ok
bool b = !is; // ok

what does if(! (is s)) mean?

The is >> s attempts to read the string s from stream is.

istreams operator>>() returns a reference to is.

istreams operator!() tests if the stream is in an invalid state. Specifically, it returns true if the stream's badbit or failbit has been set.

So,

 if (! (is >> s) )
return is;

is functionally equivalent to

 is >> s;
if (is.fail()) return is; // is.fail() returns true if failbit or badbit are set

which means that the function immediately returns if reading a string from the stream fails. Note that this is distinct from reaching the end of the stream.



Related Topics



Leave a reply



Submit