I'm having a trouble when I use while(cin) with struct. Would someone please make me clear about this problem? I don't know whether this kind of post was asked or not. If it was please forgive me and my bad english as well.
struct ThiSinh{
string m_HT;
float m_H;
};
I overload operator >> for it
bool operator >> (istream& is, ThiSinh &ts){
getline(is, ts.m_HT);
is >> ts.m_H;
is.ignore();
return ???;
}
Because while (cin >> ThiSinh) require a bool type, so I dont know what number or data it should return. And how to break the while loop when I press ctrl + Z.
I have also tried
while(cin){
ThiSinh ts;
cin >> ts;
}
and it worked but I dont want to get that false data. So someone please helps me out. Thanks in advance.
Your operator >> returns a bool, which is extremely unusual for a stream extraction operator, and renders it unusuable in most streaming contexts. Such operators are expected to return a reference to the stream on which they operate:
istream& operator >> (istream& is, ThiSinh &ts){
getline(is, ts.m_HT);
is >> ts.m_H;
is.ignore();
return is;
}
This is how multiple exrtactions actually work:
std::cin >> a >> b >> c;
Effectively, this first does auto &tmp = operator>>(std::cin, a), and then calls operator>>(tmp, b), and so on.
The reason why streams (and by extension, stream extraction operations) can be used in conditionals is that std::istream (and std::ostream) defines a conversion to bool (which returns true iff the stream is in error-free state); that conversion is then invoked by the conditional.
In other words, this:
while (std::cin >> ts)
effectively becomes this:
while (static_cast<bool>(operator>>(std::cin, ts)))
and the cast is possible because operator>> returns std::istream& and std::istream defines a conversion to bool.
Related
istream& operator>>(istream& is, State& s){
uint16_t first;
int second;
char delim;
is **>>** first >> delim >> second >> delim; //For player in Room.
for(GameObject* i : GameObject::GameObjects){
is **>>** first >> delim >> second >> delim;
s.containerObjects.insert(pair<int, int>(first, second));
}
s.containerObjects.insert(pair<int, int>(first, second));
return is;
}
The starred input operators are giving me an error from clang: 'Invalid operands to binary expression (std::istream and uint16_t).
The data in the file looks like so:
0:1|2:2|3:4|
Can anyone help me to understand why?
Thanks!
Edit: Original operator usage:
file >> currentState;
Error message: 'Invalid operands to binary expression (std::istream and uint16_t) says it all. There is no >> operator defined for type uint16_t. Try >> into a normal int type and then static_cast<unint16_t> the value and put it in your variable "first".
I didn't include iostream... however I was still able to use istream and ostream with basic strings, so I guess that is a built in thing?
Im working with the book SFML Game Development by Examples and I dont really get what this sentence does. I've never seen something like this
void Anim_Directional::ReadIn(std::stringstream& l_stream){
l_stream >> m_frameStart >> m_frameEnd >> m_frameRow
>> m_frameTime >> m_frameActionStart >> m_frameActionEnd;
}
In C++ they got the "bright" idea of overloading the rightshift and leftshift operators with streams to represent serialization/deserialization.
stream >> var
means "read var from stream".
Symmetrically
stream << var
mean "put var into stream"
The operation of "streaming" in or out also returns the stream, so you can chain operations like:
stream >> var1 >> var2;
Note that the "streaming" was chosen just because of the look and because the priority was considered reasonable, but it's still just an overloaded operator and implies for example no strict sequence of evaluation. For example in:
stream << f() << g();
may be function g is called (somewhat surprisingly) before function f.
NOTE: the sequencing problem was handled by hammering this special case in last C++ standard (C++17). While it doesn't hold in general it's guaranteed for shift operators (presumably for this specific reason). So in f()+g() may be f is called later than g, but in f()<<g() this cannot happen.
C++ allows you to overload >> and << operators. std::stringstream is a derivative of std::istream and it inherits the >> operator overloads of std::istream.
The std::istream has a bunch of overloads for many common types. You can find a list of them here.
A typical std::istream >> operator overload looks as follows:
std::istream& operator>>(std::istream& stream, YourType& var) {
/*
** code here to parse and read a 'YourType' into 'var'
*/
/* var is set */
return stream; /* return the same stream to allow chaining */
}
When you do some_stream >> YourType_object, the matching >> operator overload is invoked. In the aforementioned case, our operator overload is invoked with stream parameter taking some_stream and var taking YourType_object.
The >> overloads (and << overloads too) intelligently return the stream which they operated; thereby, allowing a series of >> operators to be chained.
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
Book.h:
#ifndef BOOKDATE
#define BOOKDATE
#include <iostream>
#include <string>
class Book{
friend std::istream& operator>>(std::istream&, Book&);
private:
std::string title, author;
int number;
};
std::istream& operator>>(std::istream&, Book&);
#endif // BOOKDATE
Book.cpp:
#include "BookDate.h"
using namespace std;
istream& operator>>(istream& is, Book& rhs){
getline(is, rhs.title);
getline(is, rhs.author);
is >> rhs.number;
if(!is)
rhs = Book();
return is;
}
I was wondering how exactly I should approach creating the input operator for the Book class. The title and author will be more than one word, so it fits that I need to use getline to receive that data. The issue then with getline is that it may pick up any '\n' left in the stream since cin was last used. For instance;
int x;
cin >> x; //newline is not extracted and left behind
Book a;
cin >> a; //"title" is automatically made empty!
I could instead use cin.ignore(256, '\n') but whose responsibility, the user's or class author's, is it to use this? Does the user use .ignore before he inputs a Book object or does the class author put .ignore at the beginning of the input operation?
It seems that in the former case the user would have to understand an .ignore method is needed but in doing so has to understand the implementation of the Book's input operator, which is not desirable. In the latter case, putting .ignore in the operator means my operator may not adapt to certain circumstances, since it always expects to encounter a newline before processing. For instance reading from an input file with data such as:
book1
author1
1
book2
author2
2
Means book1 gets ignored by cin.ignore(256,'\n').
To make your operator>> behave more like the operators for the built in types, you can use the ws manipulator to skip whitespace before you read your input.
Just use
is >> ws;
at the beginning of your input operator, and the stream will be positioned at the first non-whitespace character after the current position.
To overload the extraction operator properly you can change your input format to be a sequence of three variables that you want to populate, namely:
(title, author, number)
and modify your operator>> to:
istream& operator>>(istream& is, Book& rhs){
// just a suggestion: it is better if there is no input to do nothing
if(!is) return is;
string title, author;
int number;
char par1, comma, par2;
cin >> skipws >> par1 >> title >> comma >> author>> comma >> number >> par2;
if (par1 != '(' || comma != ',' || par1 != ')'){
// set failbit to indicate invalid input format
is.clear(ios_base::failbit);
}
rhs(title, author, number);
return is;
}
put is.ignore(); before getline(is, rhs.title);
I read this on Accelerated C++. Here is a simplified version.
istream& read_hw(istream& in, Student_info& s)
{
in >> s.name >> s.midterm >> s.final;
return in;
}
Then, we can call the function as:
Student_info s;
read_hw(cin, s);
My question is,
What's the point of returning the reference to istream? Since both the two parameters are passed by reference;
While calling the function, we don't seem to care about the returning value
You should read the next paragraph:
Returning the stream allows our caller to write
if (read_hw(cin, homework)){/*...*/}
as an abbreviation for
read_hw(cin, homework);
if (cin) {/*...*/}
Returning the reference to istream enables cascading. For example:
int i, j;
std::cin >> i >> j;
// Equivalent to std::cin.operator>>(i).operator>>(j);
istream::operator>>() returns istream& so that the cascaded >> works.