Ofek Shilon Ofek Shilon - 8 days ago 7
C++ Question

Implicit conversion of stream to bool

Take this toy code:

#include <iostream>
#include <fstream>

int main() {

std::ifstream is;
// perform read
// ...
if (!is) // works
std::cout << "fail";
if( is == false) // error C2678
std::cout << "fail";

return 0;
}


You'd get the following counter-intuitive results:
if(!is)
compiles, and
if(is==false)
gives


error C2678: binary '==': no operator found which takes a left-hand
operand of type 'std::ifstream' (or there is no acceptable conversion)


(for VS2015 - similar errors in gcc and clang).

The standard says (according to this answer):


Valid C++ 2003 code that relies on implicit boolean conversions will
fail to compile with this International Standard. Such conversions
occur in the following conditions:


  • passing a value to a function that takes an argument of type bool;

  • using operator== to compare to false or true;

  • returning a value from a function with a return type of bool;

  • initializing members of type bool via aggregate initialization;

  • initializing a const bool& which would bind to a temporary.




As far as I can tell
if(is==false)
is explicitly required to fail, but how come
if(!is)
doesn't? Doesn't it qualify as an 'implicit boolean conversion'?

Was this conversion-to-bool deliberately omitted from the cases listed in the standard? Perhaps it's an unintentional omission?




Edit:
This code fails just as well:

int main() {

std::ifstream is;
// perform read
// ...
if (is) // works
std::cout << "success";
if( is == true) // error C2678
std::cout << "success";

return 0;
}


And here the presence of operator!() is irrelevant.

Answer

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
Comments