6

I'm curious how the fstream class is able to return a true or false value by simply placing the name of the object inside a conditional statement. For example...

std::fstream fileStream;
fileStream.open("somefile.ext");

if (!fileStream)  // How does this work?
  std::cout << "File could not be opened...\n";

I ask this because I want my own class to return a value if I use it in a similar way.

  • 3
    This is known as the [safe-bool idiom](http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Safe_bool), and should not be used in new C++11 code in favor of `explicit operator bool()`. – ildjarn Apr 11 '12 at 00:18
  • That's right. I totally forgot about this. I can't mark your comment as the answer, but thanks! –  Apr 11 '12 at 00:26

2 Answers2

6

It's not really that it is equal to true or false, but rather that it overloads the ! operator to return its status.

See http://www.cplusplus.com/reference/iostream/ios/operatornot/ for the details.

Doing this yourself is very simple, check out the operator overloading faq or C++ Operator Overloading Guidelines.

Edit: It's been pointed out to me that ios also overloads the void * conversion operator, returning a null pointer in the case of a failure. So you could also use that approach, also covered in the previously mentioned faq.

Community
  • 1
  • 1
jli
  • 6,523
  • 2
  • 29
  • 37
  • oh, obviously I could test this my self, but you are saying that if I were to type if (fileStream) that would not work the same way? –  Apr 11 '12 at 00:17
  • 2
    It doesn't overload `operator!`, it uses a conversion operator `operator bool` – bames53 Apr 11 '12 at 00:19
  • @bames53 Really? I always thought it was just the not operator (of course I could be wrong). Do you have a link to a document saying that? – jli Apr 11 '12 at 00:21
  • What it actually overloads is `operator void *`, which returns a null or non-null pointer to indicate the state of the stream. This is called the safe-bool idiom, because it allows it to be tested as a `bool`, but prevents it from being implicitly converted to `int`, as can happen if you overload `operator bool`. – Jerry Coffin Apr 11 '12 at 00:22
  • Makes sense, just saw http://www.cplusplus.com/reference/iostream/ios/operator_voidpt/ – jli Apr 11 '12 at 00:22
  • I totally forgot I can overload operators int, double, etc.. That was the answer I was looking for! Thank you. –  Apr 11 '12 at 00:27
  • I guess operator bool specifically was only added in c++11: http://en.cppreference.com/w/cpp/io/basic_ios/operator_bool – bames53 Apr 11 '12 at 00:40
  • It's important that you not have to use `operator!` because otherwise the nice idiom `if(std::fstream fin{"..."}) { /* use fin here */ }` wouldn't work. – bames53 Apr 11 '12 at 00:49
3

This works using a conversion operator. Note that the seemingly obvious way, conversion to bool, has unintended side effects, therefore a conversion to a built-in type with implicit conversion to bool should be used, e.g.:

class X
{
public:
  void some_function(); // this is some member function you have anyway
  operator void(X::*)() const
  {
    if (condition)
      return &X::some_function; // "true"
    else
      return 0; // "false"
  }
};

In C++11, you can make the conversion to bool explicit, and thus avoid the unintended side effects. Thus in C++11 you can simply write:

class X
{
public:
  explicit operator bool() const
  {
    return condition;
  }
};
celtschk
  • 19,311
  • 3
  • 39
  • 64
  • Thank you for the explanation. Together with the others, it all makes sense. –  Apr 11 '12 at 06:52