std::stringstream - string to number working - c++

I am learning C++ and I'm in doubt on how the following code works. My aim is to accept numbers (as a std::string) from the Command Line separated by spaces and separate these numbers from the string. I posted another question related to this and got the program working using the code below. Can you please explain to me how the numbers are actually extracted from the strings?
string gradesFullLine;
getline(cin, gradesFullLine);
stringstream gradeStream(gradesFullLine);
for(gradeStream >> grade; gradeStream; gradeStream >> grade) {
grades.push_back(grade);
}

Here's a simpler way to write the loop:
while(gradeStream >> grade) {
grades.push_back(grade);
}
Here's how it works:
gradeStream >> grade invokes operator>>(std::istream, int) (or whatever numeric type grade is). This attempts to "extract" a number from the stream, and updates the "stream state" indicating success or failure.
The result of the expression gradeStream >> grade, i.e. the return value of operator>>(std::istream, int), is gradeStream itself.
Any standard stream has a method equivalent to operator bool() const which lets you use the stream in a boolean context, such as an if() or while() condition. This operator returns true if the stream is "good" meaning it has not had any I/O errors (including reading past the end of the stream).
So the boolean value is used as the while condition, meaning that the loop will be entered so long as gradeStream has a "good state" which means grade has been populated with a number extracted from the stream (how this extraction happens is defined by your particular system implementation).

Related

How is "std::cin>>value" evaluated in a while loop?

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.

Verifying variable type

I was trying to verify if the entered value was an integer with the type id function. I know that the returned value would be i and not integer. I don't know why any entered value returns false and the programs stops. Any help would be appreciated.
The program works fine without the while statement
#include <iostream>
#include <typeinfo>
using namespace std;
int main() {
int number, factorial;
cout << "Enter a number: ";
cin >> number;
factorial = 1;
while (typeid(number).name() == "i") {
for (int i = number; i >= 1; --i){
factorial *= i;
}
cout << factorial;
}
}
The returned string of the member function name of std::type_info is implementation defined. It's not guaranteed to be "i". If you want to check the type of an object against another type you should do:
typeid(object) == typeid(T)
for any T type. In your example:
typeid(number) == typeid(int)
But the above comparison will always return true because number is declared as int. typeid is usually helpful to inspect the dynamic type of a polymorphic object. In your case number is not polymorphic at all. Therefore you don't need it.
What you seem to be worried about is validation of the input. For that you should consider that if operator>> of std::cin fails the following will happen:
(until C++11)
If extraction fails (e.g. if a letter was entered where a digit is expected), value is left unmodified and failbit is set.
(since C++11)
If extraction fails, zero is written to value and failbit is set. If extraction results in the value too large or too small to fit in value, std::numeric_limits<T>::max() or std::numeric_limits<T>::min() is written and failbit flag is set.
Therefore all you need to do is check the fail bit right after requiring it:
std::cin >> number;
if (std::cin) {
// ...
}
When streams read to an object, they check the format that's being read and parse that format into the object. If the stream cannot correctly parse that data, it sets an error in its error mask. The error mask is used to determine if an I/O operation succeeded or failed. When a stream is put into a boolean context (like in the parameters of an if() or while() loop), it will return true if its error mask is free of any errors.
If your intention is to only use an integer, then I suggest you adopt the pattern of using the stream itself to check if I/O operations succeeded. For example, this is how it will look in your code:
if (std::cin >> number) {
...
}
The formatted extractor operator>>() returns a reference to the stream which will then call its member function explicit operator bool() const to access its stream state and return true or false depending on whether the stream successfully read the contents of the stream into number.

invalid numbers always fall to 0?

cout << "Enter a positive integer or zero: ";
getline(cin, streamStr);
stringstream(streamStr) >> number;
if (!number) {
cout << "invalid input detected or the input is too big.\n";
return 1;
}
inputs like "%234" or "sdf2334" always fall to 0 , which is false in bool expression, but 0 is still a number.
How to check if the input is really invalid like "%234"??
You need to check the returned value of the operator>>, which is not the same as the value of the variable you're reading into:
if (stringstream(streamStr) >> number) {
...
So what's the returned value, then? If you check the docs, you'll see it's a stream itself. It goes to the operator bool of it (because it's used in an if statement), which in turn returns the validity of the stream, or, IOW, if the last operation succeeded.
If you want to ensure the stream doesn't contain anything besides the number use
if (sstream.rdbuf()->in_avail() > 0) {
// something is still there
And to skip whitespace at the end if you want to allow it:
sstream >> std::ws;
So, all in all...
template<typename T,
// those are optional
enable_if<is_default_constructible<T>::value>::type,
enable_if<is_input_streamable<T>::value>::type
>
optional<T> myRead(string input, bool allowTrailingWs = true) {
stringstream str(input);
T val;
// check parsing
if (!(str >> val))
return none;
// allow whitespace at the end
if (allowTrailingWs)
str >> std::ws;
// check if there's any garbage left
if (str.rdbuf()->in_avail() > 0)
return none;
return val;
}
The code above is just for illustration purposes. Shall you need more advanced parsing, check out Boost.Spirit.
Also, apparently this isn't guaranteed to work every time. Using:
auto inputEnd = ss.tellg();
ss.seekg(0, std::ios::end);
if (inputEnd == ss.tellg()) {
To check if the ss is empty could help fix that.
I don't think you understand how streams work. Allow me to address your misconception:
The stream won't attempt to extract any value into number if the data being evaluated doesn't correspond to formatting requirements of the type. Extraction works by the stream iterating through each character in the character sequence one by one, and testing each character as a viable datum for the type to which the extraction is targeted. If the character is not viable, extraction stops (this is why you are seeing success upon entering something like "2342fdsf"; the stream will keep extracting until it finds an invalid character. "2342" are valid characters for an integer while "f" is not)
If the stream finds an invalid character, nothing further is done to the variable (in this case number). In fact, it is implementation-defined what value an uninitialized variable has if extraction failed to produce any characters. With that in mind, it is potentially dangerous to check the value of the operand to determine if I/O failed. This is where checking the stream state comes in:
std::istringstream iss(streamStr);
if (iss >> number)
{
std::cout << "Extraction produced: " << number << '\n';
}
If the extractions fails, the stream will set the appropriate bits. The stream will then be implicitly converted to a boolean using operator bool() (or operator void*() pre-C++11 where it will subsequently undergo conversion to boolean). The boolean function will check the stream state using !this->fail() (which checks both badbit and failbit) and if the function returns true, the if body will be executed.
If the stream is not in a good state (!this->fail() returns false), that means the extraction failed to produce a value and the if statement body goes unevaluated.
By encasing the extraction in a conditional check, not the value of the thing you tried to extract into.
Assuming number must be a char value, try using the cctype library which is helpful for dealing with strings. It has functions such as
isdigit(Char_Exp) //Returns true if the value is a digit
and
isctrl(Char_Exp) //Returns true if the value is a control character like %(modulus)
Here is a link to a C++ cctype library reference: cctype library reference
To test number I would advise you create a function of type Boolean and so that it tests all possible input errors at once.

How to stop reading using >> when there are no more word left

I am given a list of words in a text file, all seperated by newlines. Reading them using fstream and >>, and not knowing the amount of words there are. How do I tell the program when to stop? I've tested it out, and the value of the variable just stays the same of the last word read.
Checking the state of the stream after extraction is always a good idea. It tells you if there were any problems while performing the extraction, or whether the file stream has reached the end-of-file character (EOF).
The latter case is what you're dealing with. All you need to do is perform the extraction while the stream is in a good state, which is idiomatically done in the following way:
while (in >> str) {
// ...
}
After the stream performs the extraction, operator bool() is invoked, which calls !fail(). Using a while loop will allow the next extraction to be performed automatically. It will stop when the stream has performed an incorrect extraction, is perhaps out of memory, when it hits the EOF character, or some other user-defined situation.
You've failed the fundamental principle of I/O: You must check whether your input operation succeeds. You cannot know that in advance, you only learn that after you have tried:
for (std::string word; std::cin >> word; )
// ^^^^^^^^^^^^^^^^<----------- test for success
{
std::cout << "Here is one word: " << word << std::endl;
}
You have to remember that the input operator >> returns the stream it uses, and that streams can be used as boolean conditions. That means you can use it as a loop condition:
while (some_stream >> some_variable)
{
...
}

How to cover all possible data types when declaring a function parameter?

I'm attempting to construct a function that will perform a sanity check on the user's response to a number of questions, each of which would ideally be a non-zero integer. How can I construct a function that would be able to accept a parameter of any data type, but only have a single parameter? For example:
bool SanityCheck(<type id> number)
where <type id> would cover any data type.
It's not clear exactly what you really want here. Unverified input from a user normally comes in the form of a string. Typically you read in a string, verify that it has the desired form (e.g., for an integer, all digits). If it has the right form, you convert that to the desired type, and use it. If it doesn't, you ask the user to re-enter their data, usually with a prompt like "Please enter an integer between 1 and 10".
A function template is sort of a direct answer to the question you asked, but I have a hard time imagining it being of any help in a situation like you've described. A function template is most often of use in cases where you have to carry out some operations that are syntactically the same across a number of types. For example, it lets you add two numbers, regardless of whether those happen to be of type short, int, long, float, double, long double, etc. That only works because they're really all numbers, and you can reasonably use + to add any of them together.
When you're dealing with some unknown input, that doesn't apply though -- you need to verify enough about the data to be sure the operation is sensible and meaningful before you can do much else with it; it's pretty hard to get a meaningful result from comparing (for example) 7 to a sunset.
C++ is a statically typed language. What type a variable is of will be fixed at compile-time and cannot be changed at run-time. What users enter, however, will only be known at run-time, and cannot be known at compile-time. Therefore your question makes no sense.
When you expect an integer from a user, then the best way would be to try to read an integer, and check whether this succeeds:
int i;
std::cin >> i;
if(!std::cin)
throw "Stupid user blew it!"; // or some real error handling
However, the catch with this is that, once an input operation fails, an input stream enters a bad state and the data that couldn't be read stays in the input buffer. If you want to handle this gracefully, would have to clear the stream's error state flags, and make it ignore whatever is in the input buffer.
So sometimes it might be easier to first read a string
std::string input;
std::cin >> input; // either read up to any whitespace, or
std::getline(std::cin, input); // newline, or
std::getline(std::cin, input, '\t'); // tab, or whatever you want
because this always succeeds, and then try to convert it into whatever data you need. The way to do this is via string streams:
std::istringstream iss(input);
int i;
iss >> i;
Now you can check the string stream's state
if(!iss)
and if the conversion failed, std::cin will still be usable and the erroneous input read from its buffer.
However, there's one more catch: If a user inputs '"42 thousand"', then this won't catch the error. The remaining characters will be in the string streams input buffer and silently ignored. So what you usually need to do for such a conversion is to test whether the string stream's buffer is fully read, that is: reading reached EOF. You can check for this by invoking iss.eof(). However, if you read a whole line, there might be extra whitespace at the end, which you wouldn't want to make the conversion fail, so you need to read extra whitespace before you check for EOF: iss >> std::ws. (std::ws is a stream manipulator that "eats" consecutive whitespaces.)
by now, the conversion would look like this:
std::istringstream iss(input);
int i;
iss >> i >> std::ws; // you can chain input
if(!iss.eof())
throw invalid_input(input);
Of course, this is pretty elaborated for a one-time conversion and I wouldn't exactly swear by the life of my kids that there isn't a nice improvement left that I hadn't thought of yet. So you would at least want to wrap this into a function and put that into your toolbox for reusing it (and improving on it, if you find an error):
bool convert_to_int(const std::string& str, int& result)
{
std::istringstream iss(input);
iss >> result >> std::ws;
return iss.eof();
}
Or, generic for any type:
template< typename T >
bool convert_from_string(const std::string& str, T& result
{
std::istringstream iss(input);
iss >> result >> std::ws;
return iss.eof();
}
Even better would be to use a ready-made off-the-shelf solution for this. Boost has just such a thing with its lexical_cast.
Here's a skeleton algorithm for the whole input routine:
int i;
do {
read string input
convert to int i
while(!conversion succeeded);
With the bits from further above, you should be able to fill in the missing parts.
Use templates:
template <typename T>
bool SanityCheck(T number);
The sanity check may vary for different types. As this is a homework, I won't post any more code just hint you with a Google search term "partial template specialization".
Ok, I think I get what you actually want now.
I imagine your situation is something like this:
Read some user input (maybe using std::cin).
Check to make sure it is an int.
Use the int if it is one.
If this is the case then you do not want a function that can handle different data types, because the user cannot enter different data types, he can only enter characters and you have to choose what datatype you want to store that as.
I think this is what you need:
bool valid = false;
int input = 0;
while (!valid)
{
std::string inputStr;
std::cin >> inputStr;
valid = isInteger(inputStr);
if (!valid)
std::cout << "Please enter an integer." << std::endl;
else
input = atoi(inputStr.c_str());
}
std::cout << "You entered " << input << "!" << std::endl;
You're going to have to write isInteger yourself, but hopefully you get the idea.
Option 1: use boost::variant if you want it to be a single function
Option 2: overload this function for all types that you need
Making your function a template function would achieve this.
template<typename T>
bool SanityCheck(T number);
A lot of online surveys that I'm asked to fill out don't ask me to enter data but only select an option from 1 to 5. 1 = Totally Agree, 5 = Totally Disagree. This seems a more efficient way of collecting user input since you have total control over data type and all I have to do is highlight an option box.