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 aswhile(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
.
istream
s operator>>()
returns a reference to is
.
istream
s 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
How to Assert If a Std::Mutex Is Locked
Linux C++ Error: Undefined Reference to 'Dlopen'
Why Is a NaïVe C++ Matrix Multiplication 100 Times Slower Than Blas
How to Monitor a Folder with All Subfolders and Files Inside
String Conversion with Boost Locale: Different Behaviour on Windows and Linux
How to Avoid Multiple Definition Linking Error
Find Argc and Argv from a Library
Openprocess/Readprocessmemory/Writeprocessmemory/Closehandle Equivalent
Press Anykey to Continue in Linux C++
Determine If Linux or Windows in C++
Get Computer Name and Logged User Name
How to Force Linker to Use Shared Library Instead of Static Library
Using Qsocketnotifier to Select on a Char Device
How to Compile SQLite with Icu
Colour Output of Program Run Under Bash
Is a Pointer with the Right Address and Type Still Always a Valid Pointer Since C++17