Step 6 of 6
Challenge: operator>> for your own type
You've seen that operator<< teaches std::cout to print your types. The reverse, operator>>, teaches any input stream to read them. Once it exists, std::cin >> p, file >> p and while (in >> p) all just work.
The conventions for a good operator>>:
- Take the stream and the target by reference, and return the stream, so reads can be chained:
in >> a >> b. - Read into temporaries first, and only change the target when the whole value was read correctly.
- If the text is malformed, call
in.setstate(std::ios::failbit). That makes the stream convert tofalse, which stopswhile (in >> x)loops, just like readingabcinto anintwould.
#include <iostream>
#include <sstream>
struct Time {
int h = 0, m = 0;
};
std::istream& operator>>(std::istream& in, Time& t) {
int h, m;
char colon;
if (in >> h >> colon >> m && colon == ':' && h >= 0 && h < 24 && m >= 0 && m < 60) {
t = {h, m};
} else {
in.setstate(std::ios::failbit);
}
return in;
}
int main() {
std::istringstream in("9:30 13:05 25:00 18:00");
Time t;
int total = 0;
while (in >> t) {
std::cout << "read " << t.h << "h" << t.m << "\n";
total += t.h * 60 + t.m;
}
std::cout << "minutes " << total << ", stopped early: " << !in.eof() << "\n";
}
read 9h30
read 13h5
minutes 1355, stopped early: 1
Reading the example
25:00has the right shape but an invalid hour, so the operator setsfailbitand the loop stops.18:00is never read.tstill holds13:05after the failure, because rule 2 kept the bad value out.- After the loop,
in.eof()tells the two endings apart:truemeans the input simply ran out,falsemeans a bad value stopped it.
The format for your task
Your Point uses the text (x,y). The same recipe applies: read into temporaries, check every piece of punctuation, and only then assign.
char open, comma, close;
int x, y;
if (in >> open >> x >> comma >> y >> close && open == '(' && comma == ',' && close == ')') {
p = {x, y};
} else {
in.setstate(std::ios::failbit);
}
return in;
Chars and whitespace
in >> ch for a char skips spaces first and then reads one character. So ( 3 , 4 ) with spaces would also parse with the pattern in your task, which is usually what you want. When checking punctuation, compare every character you read: accepting [3,3] as a point would be a bug.
Your turn: write operator>> for Point using the (x,y) format above. The provided main reads points until one fails, then prints the path length (sum of Manhattan distances between consecutive points) and whether the input ended cleanly.