I thought that:
if (true)
{execute this statement}
So how does if (std::cin >> X) execute as true when there is nothing "true" about it? I could understand if it was if ( x <= y) or if ( y [operator] x ), but what kind of logic is "istream = true?".
The answer depends on the version of the standard C++ library:
Prior to C++11 the conversion inside if relied on converting the stream to void* using operator void*
Starting with C++11 the conversion relies on operator bool of std::istream
Note that std::cin >> X is not only a statement, but also an expression. It returns std::cin. This behavior is required for "chained" input, e.g. std::cin >> X >> Y >> Z. The same behavior comes in handy when you place input inside an if: the resultant stream gets passed to operator bool or operator void*, so a boolean value gets fed to the conditional.
std::cin is of type std::basic_istream which inherits from std::basic_ios, which has an operator : std::basic_ios::operator bool which is called when used in if statement.
if(x) is equivalent to if(bool(x))
in this case bool(x) calls std::istream::operator bool(x)
this will return:
true if none of failbit or badbit is set.
false otherwise.
What is inside if condition will be evaluated to bool.
if(cin >> X) means that if condition is true, something was read to X; if condition is false, something else happened (e.g. stream ended) and X is not changed.
E.g. to read until the end of stream, you can use while(cin >> X).
Related
Consider this snippet:
int a;
while (cin >> a){/* do something */}
On running this code, suppose I enter a string. The loop is exited. But then, since the expression inside while ends in error, and it doesn't evaluate to a bool type (is this incorrect thinking?), how does the compiler know to exit the loop?
cin >> x returns cin to allow chaining.
And in an boolean context, cin evaluates to true if and only if the last operation was successful.
Long story short, the loop will end on the first end of file or error.
cin >> a will always return a reference to cin.
The std::basic_ios base class has an explicit operator bool() that will be invoked when cin is "evaluated" in the condition of if, while, or for. When the operation fails, then failbit is set in the flags and the next time cin is converted to bool, the result is false because of the flag.
When you do
cin >> a
You call the basic_istream& operator>>( int& value ); and as you can see it returns basic_istream& so basically you have
while(cin)
and what that does is call
explicit operator bool() const;
which will return true if the stream is not in an error state and false if it is in an eror state. That is why the loop ends when there is an error.
The condition in while (cin >> a) is not when a != 0, but when std::cin is valid.
std::cin becomes invalid if you input string instead of int or if stream ends for example.
The class std::basic_ios, the base class of the class std::istream, has the conversion operator
explicit operator bool() const;
that returns true if the condition !fail().is true.
So if an error occurs in this statement
cin >> a
that returns the stream std::cin itself then it is contextually converted to the type bool with the value false and this loop
while (cin >> a){/* do something */}
does not execute its sub-statement.
I have this snippet of code, which has the purpose of defining the >> operator for a struct point (it's not the whole function, just the beginning).
struct Point {
int x;
int y;
};
The code snippet
istream& operator>>(istream& is, Cord::Point& p) {
char ch1;
if (is >> ch1 && ch1 != '(') { // Is this not a point?
is.unget();
is.clear(ios_base::failbit);
return is;
}
//More code...
}
should function by checking if the input if the first character is ( essentially checking if it should proceed in assuming this point is the form of (x, y). I understand what the
ch1 == '(' is doing but what is the purpose of is >> ch1. It must be a boolean, but it seems to always be false because this check always fails from my testing.
what does testing an “stream >> char” [is >> ch1] do?
>> is the stream extraction operator. Given a character operand, it extracts a single character from the stream, and assuming no error occurs, assigns the value to the operand.
It must be a boolean
The stream extraction operator returns the stream. The stream converts implicitly to bool. The converted value is true if the stream has no errors and is ready for I/O operations and false otherwise.
Here is an overloaded >>operator function:
std::istream& operator>>(std::istream& is, std::vector<int>& v){
string s;
if (! (is >> s) )
return is;
...
return is;
}
To my understanding, if(! (is >> s)) make no sense because the terminal or console will wait until the input from keyboards or other sources enter s. So value of condition in if() will ultimately be false. Who can help?
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.
istream does not have to be a console. It can be a stringstream. And besides, the 'waiting for user input' is not seen by the application code. It is asleep while the input stream is being filled (by the operating system, underlying library, ...)
Anyhow: in case the input stream contains no data at all, this condition will be true.
std::string s; // empty!
std::stringstream ss(s);
std::vector<std::string> strings;
ss >> strings; // should be empty!
To understand what if (!(is >> s)) means you need to understand what if (is >> s) means.
Since is is an std::istream, operator >> returns an std::istream. Hence, is >> s is an std::istream, which inside an if must produce a logical value true or false. This Q&A explains how it is done in different versions of C++. Essentially, std::istream evaluates to a true condition when the operation is successful.
Now that you know the meaning of is >> s, you can figure out that adding a negation flips that meaning: !(is >> s) would be true only when reading an s from is is unsuccessful. For strings an unsuccessful read means that the stream is in an invalid state, for example, because the end of stream has been reached.
you are doing many things in one line
! (is >> s)
you take the inputstream and use it to assign the object s, the evaluate teh result of s in the if condition
Currently I'm self-learning C++ Primer 5th. Here comes something I'm not sure. (I couldn't find the exact relevant question on F.A.Q).
Consider this while loop:
while(std::cin>>value){...} \\value here was defined as int.
The text book says:
That expression reads the next number from the standard input and stores that number in value. The input operator (§ 1.2, p. 8) returns its left operand, which in this case is std::cin. This condition, therefore, tests std::cin.When we use an istream as a condition, the effect is to test the state of the stream. If the stream is valid—that is, if the stream hasn’t encountered an error—then the test succeeds.
My question is: does std::cin read input into value first then test the validation of std::cin, or test std::cin first then decide whether to read into 'value'? I'm quite confused about when it "returns its left operand".
Remember that your code is equivalent to:
while (std::cin.operator>>(value)) { }
Or:
while (1) {
std::cin >> value ;
if (!std::cin) break ;
}
The "code" always tries to read from std::cin into value before testing std::cin.
Let's look at the quote:
[...] The input operator (§ 1.2, p. 8) returns its left operand, which in this case is std::cin. [...]
This only means that std::cin.operator>>(value) return std::cin.
This condition, therefore, tests std::cin. When we use an istream as a condition, the effect is to test the state of the stream. If the stream is valid—that is, if the stream hasn’t encountered an error—then the test succeeds.
What the text book says is that after trying to read an integer from std::cin to value, the >> operator returns std::cin. If std::cin is in a good state after reading value, then the test passes, otherwize it fails.
Some extra details:
When you do std::cin >> value, you basically call istream::operator>>(int&), and yes there is a test inside that method: If the test passes, then the internal state of std::cin is set to ios_base::goodbit, if it fails, internal state is set to on of the error flag (eofbit, failbit or badbit).
Depending on the exception mask for std::cin, if the internal test fails, an exception may be thrown.
From your quote:
When we use an istream as a condition, the effect is to test the state of the stream.
This basically mean that:
if (std::cin) { }
Is equivalent to:
if (!std::cin.fail()) { }
And std::cin.fail() check for failbit or badbit. This means that while (std::cin >> value) { } does not test the eofbit flag and will only fail when the input cannot be converted to an integer value.
does std::cin read input into value first then test the validation of
std::cin, or test std::cin first then decide whether to read into
'value'
cin first tries to read an int from the standard input, if cin is in a good state: if it fails to, it will set the stream to a bad state; regardless of the operation done, it will return the stream itself (i.e. the "left operand" -- cin), that will allow you to check for success or failure.
If you wanted to explicitly test the validity of the stream first and only then try to read the value, you would have:
while (cin && cin >> value)
but it's pretty redundant, since, as I've told you, cin will not even try to read value if it's already in a bad state.
There are two tests.
The first test is the condition of the while statement
while(std::cin>>value){...}
This condition tests the result of calling operator function operator >>
The second test is a condition within the operator. If the state of the stream std::cin is good then the function tries to read an integer from the string. Otherwise it returns std::cin with the current erroneous state of std::cin.
In the while condition there is an expression
std::cin>>value
This expression must be evaluated. So this condition tests the result of the call of operator >> .
The result of the operator is the stream std::cin But it can be contextually converted to a bool value due to operator
explicit operator bool() const;
which returns the state of the stream
!fail().
I assume your "value" is for example an int
The stream tries to read input until the next whitespace.
if eof is found ... -> then the state will be set to "eof", >> will return the stream and the boolean evaluation of the stream will return false
if an error (I/O for example) happens during the reading process, the state will be set to "bad", >> will return the stream and the boolean evaluation of the stream will return false
if whitespace has been found, then a conversion from the read characters to int (the above assumption) will be attempted. If it fails (because the read input is for example: "xx" and not a number) the state of the stream will be set to "fail". >> will return the stream and the boolean evaluation of the stream will return false
if we are so far down the chain, eof was not found, no IO error (or other) happened, and the characters -> int conversion was successful. >> will return the stream and the boolean evaluation of the stream will return true.
And your "value" will contain the appropriate value
Presumably you wouldn't have any confusion with a simple function call:
SomeReturnType some_function(int&);
while (some_function(value)) { ... }
The above code will repeatedly call some_function until the return value from the function call, interpreted as a boolean, is false. The function is called for each step in the loop. Whether the function changes the value of value is up to the function. It certainly can do so, and presumably will do so (but that's an issue for the designer of the function).
The loop while (std::cin>>value) {...} is completely equivalent to while (std::cin.operator>>(value)) {...}. This is just a function call to the member function std::stream::operator>>(int&).
The operator first reads the value and then returns a reference to the object. The while statement first calls that operator and second tests the returned value.
I've used statements such as this quite a bit in my C++ programming:
std::string s;
std::ifstream in("my_input.txt");
if(!in) {
std::cerr << "File not opened" << std::endl;
exit(1);
}
while(in >> s) {
// Do something with s
}
What I want to know is, why does this work?
I looked at the return value of operator>>, and it's an istream object, not a boolean. How does an istream object somehow get interpreted as a bool value that can be put inside of if statements and while loops?
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())
std::basic_ios, from which the input and output streams inherit, has the conversion function operator bool (or operator void* prior to C++11 to get around the safe-bool problem, which is no longer an issue thanks to the explicit keyword).
See std::basic_ios::operator bool:
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)){...}. Such loops execute the loop's body only if the input operation succeeded.