34

I'm reading a book on C++ that says that if I use the >> operator it returns the object at the left side of the operator so in this example

std::cin >> value1;

the code returns std::cin.

But if I do this

while(std::cin >> value1)

My code will be in the loop until there is a std::cin error so that must mean that the operator returns a bool that is true when std::cin does not fail and false when std::cin fails.

Which is one is it?

Rakete1111
  • 42,521
  • 11
  • 108
  • 141
gigi
  • 629
  • 6
  • 11

4 Answers4

53

[...] so that must mean that the operator returns a bool [...]

Nope, it returns std::cin (by reference). The reason why while(std::cin >> value); works is because std::istream (which is the type of std::cin) has a conversion operator.

A conversion operator basically permits a class to be implicitly (if it is not marked explicit) to be converted to a given type. In this case, std::istream defines its operator bool to return whether an error (typically failbit) occurred;

[std::ios_base::operator bool()]

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


explicit operator bool() const;

Note than even though the operator is explicit (which shouldn't allow implicit conversions like if (std::cin);), the qualifier is ignored when used in a context that requires a bool, like if, while loops and for loops. Those are exceptions though, not rules.

Here is an example:

if (std::cin >> value);  //OK, a 'std::istream' can be converted into a 'bool', which 
                         //therefore happens implicitly, without the need to cast it: 

if (static_cast<bool>(std::cin >> value)); //Unnecessary

bool b = std::cin >> value;  //Error!! 'operator bool' is marked explicit (see above), so 
                             //we have to call it explicitly:

bool b = static_cast<bool>(std::cin >> value); //OK, 'operator bool' is called explicitly
Rakete1111
  • 42,521
  • 11
  • 108
  • 141
  • This might be less confusing for the OP if you point out that a simple `void* ptr = NULL: if (ptr)` also works (with which he or she is surely familiar), because it's _convertibility_ to `bool` that's important, rather than the actual expression having `bool` type originally. – Lightness Races in Orbit Aug 16 '16 at 22:26
  • 1
    @LightnessRacesinOrbit Good idea :) But it might be better *without* `void*, it is supposed to be avoided. – Rakete1111 Aug 16 '16 at 22:35
  • 2
    I think in addition to the exceptions from the rule it'd be useful to add a non-exception like `bool good=std::cin;`, which rightly doesn't compile. – Ruslan Aug 17 '16 at 05:19
  • @Ruslan Good idea :) – Rakete1111 Aug 17 '16 at 05:54
  • 2
    Great explanation. Instead of describing "exceptions" at all, it may be simpler to state that putting any expression in an `if` or `while` condition *is* a rather explicit cast to bool. – Drew Dormann Oct 14 '16 at 19:33
22

std::istream (the class which std::cin is an object of) has the following member function:

explicit operator bool() const;

It returns false if the object is in an error state, and true otherwise. This is why the while(std::cin >> value1) construct works. Before C++11, it had this non explicit function instead:

operator void*() const;

Which returned a null pointer if the object was in an error state, serving the same purpose.

Benjamin Lindley
  • 95,516
  • 8
  • 172
  • 256
3

Operations on streams return a reference to the stream.

So, not a bool.

You can stick the result into an if condition for the same reason that you can do this:

void* ptr = foo();
if (ptr) { /*...*/ }

And, for that matter, this:

int x = foo();
if (x) { /*...*/ }

Both ptr and x here can be converted to a bool for use in the condition. In the case of std::cin, the conversion is achieved by an operator bool() within the std::ostream class that was explicitly (pun intended) added for this exact task.

Lightness Races in Orbit
  • 358,771
  • 68
  • 593
  • 989
2

std::cin is of type std::istream (which is just a typedef of std::basic_istream<char>)

If you see the different overloaded operator>> for basic_istream, all of them are returning a reference to basic_istream. So one thing is cleared up that the operator>> here, doesn't return a bool but instead, it returns "std::cin" itself. You won't see any operator>> there returning a bool value.

So the question is now, how does it convert the std::basic_istream to bool?
The answer is: A conversion operator is being called for this purpose.

std::basic_istream inherits a operator bool() from its parent std::basic_ios

explicit operator bool() const;

which makes it possible to convert a std::basic_istream object to bool. One can easily wonder that it is marked explicit (see why is it marked explicit) and still it is implicitly converted to bool in an if or while.

The answer to this question is that if or while use the explicit conversion "implicitly". (see this answer by @R. Martinho Fernandes). So if, while and for are one of the places where this "contexual conversion" to bool happens implicitly.

Ahmad Khan
  • 2,385
  • 17
  • 25