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.
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?
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.
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 am trying to finish my lab, however I don't know how to allocate memory to a string. So I keep getting the error
warning: ‘_name’ is used uninitialized in this function [-Wuninitialized]
I don't also understand if my getline line is correct.
std::istream& operator>>(std::istream& is, Grade& RO){
int _mark;
char* _name;
std::cout<<"Subject name: ";
is.ignore();
is.getline(_name, (strlen(_name) + 1));
std::cout<<"Mark :";
is>> _mark;
RO=Grade(_name, _mark);
return is;
}
Ok #Jessica, (to general question and few info) I guess,
Grade is a class with two data members: int mark and string name. And you want to overload the insertion operator >> to populate these values.
(I recommend you leave all the cout expression outside this function). Here is one possible implementation:
istream& operator>> (istream& is, Grade& RO){
// declare local variables to insert the input values
int mark;
string name;
// extract values from input stream
is >> mark >> name;
// assuming you have member functions that set values for the object RO
RO.set_mark(mark);
RO.set_name(name);
return is;
}
I have a class template, which is -- among other things -- supposed to overload istream so it accepts the user's input and adds (pushes) it into a vector, which holds type T elements.
friend istream &operator>> (istream &in, Set<T> &s)
{
int ctr = 0;
string tmp;
T val;
while (true) {
cout << "\tElement #" << ctr + 1 << ": ";
getline (in, tmp);
if (tmp == "\0") break;
// MISSING CODE HERE: "Convert" tmp into val
s.add(val);
ctr = s.size();
}
return in;
}
This works fine with Set<string>, but I need to find a way to make it function with any primitive data type, too, i.e. Set<integer>, for example.
I tried doing
stringstream(tmp) >> val
but that then doesn't work with Set<string>.
I guess the input needs to be read in as string; how, then, do I cast the input string into T type to pass it to the .add() function?
You could use a stringstream object (created from tmp) to extract the correct value if it is not a string. Note you will have to overwrite operator>> for ostream if you need more than just the built-in types (e.g. int)
Alternatively, you can define overloads of a convert() function for each T you encounter to provide proper conversion from the string tmp to the required type. The proper overload (if exists) will be selected based on your template parameter.
You can use boost::lexical_cast to convert strings to other types lexicographically.
template<class T>
friend istream &operator>> (istream &in, Set<T> &s) {
int ctr = 0;
string tmp;
T val;
while (true) {
cout << "\tElement #" << ctr + 1 << ": ";
getline (in, tmp);
if (tmp == "\0") break;
val = boost::lexical_cast<T>(tmp);
s.add(val);
ctr = s.size();
}
return in;
}
Alternatively, you can use std::istringstream.
std::istringstream sstream(tmp);
sstream >> val;
Note that boost::lexical_cast throws an exception if the cast wasn't successful, and std::istringstream does not (you need to check this manually).
There a few issues in the code that you may like to address:
getline (in, tmp);
That need to check the return value:
if(!getline (in, tmp))
// handle end-of-file or read failure
// read okay, tmp contains the read line
Next:
if (tmp == "\0") break;
It's not very common to have embedded zeros in text files. May be this piece is trying to detect the end-of-file condition, which should be handled by checking the return value of getline or if(in) statement.
stringstream(tmp) >> val;
That creates a temporary string stream and tries to invoke operator>> on it. Well, there are two kinds of operator>> for std::istream:
std::istream member functions that accept temporary (r-values) and l-values std::istream object
free standing ones that take std::istream by reference to non-const, which don't accept r-values. (In C++11 it can accept it also as std::istream&& allowing for r-values).
Hence, the above statement can only stream into built-in types for which there is a member operator>> in std::istream.
So, that statement can be replaced with:
std::istringstream ss(tmp);
ss >> val;
That would need to have error handling again to check whether entire str was parsed into val, so, as others have said here, it's easier to use boost::lexical_cast<> that does error checking for you:
val = boost::lexical_cast<T>(tmp);
If you don't insist on reading the full line, rather reading white-space separated tokens, then the loop can look like this:
template<class T>
friend std::istream &operator>>(std::istream &in, Set<T> &s) {
int ctr;
T val;
while(in >> val) {
ctr = s.size();
std::cout << "\tElement #" << ctr + 1 << ": ";
s.add(val);
}
// end-of-file or parsing failure
if(!in.eof()) {
// handle failuer to parse or read error
}
}