Returning istream

It's not exactly a pressing issue by any standard, but as I go (again) through Stroustrup's book, something hit me: if I give members in an istream operator, why do I need to return the istream? DO I need to return it?

I ask because I noticed today when I forgot to check for (!istream) it would make it to my error check for bad read ins. I caught it, but it got me thinking: why is it needed? The code below (mostly the last few lines) is what I mean:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  istream& operator >> (istream& is, Reading& r)
//FORMAT: (1 2 3.4)
{
	char ch1;
	if (is >> ch1 && ch1 != '(') { //check if it begins a valid reading, else..
		is.unget();
		is.clear(ios_base::failbit);
		return is;
	}
	//If you made it here, it began ok
	char ch2;
	int d, h;
	double t;
	is >> d >> h >> t >> ch2;
	if (!is || ch2 != ')') { //we've went too far; bad input exits program
		cerr << "Bad reading...\n";
		exit(1);
	}
	r.day = d;
	r.hour = h;
	r.temperature = t;
	//I still don't quite understand why returning is needed if we set values
	return is;
}


If the answer is overly complicated, it's not as thought it's THAT big of a deal. "You just do" is good enough, but I wondered why. I know there's a return, and maybe it's a quirk of the language (for all I know), but it got me curious. It feels like if I'm passing it values and setting class/struct objects equal to something, did they ACTUALLY get assignment? Or is it "gathering" assignment in the istream, returning it to a class constructor, and checking it as a whole to decide if it's legal initialization?

Again, it's not a pressing matter. If anyone just wants to confirm, "No, you definitely need to, that's just the way it is, don't start thinking you're more clever than you are" that's fine
It's done so that you can do things like this for example:

std::cout << "Hello World" << std::endl;

std::cout is an std::ostream object, whose << operator returns a reference to itself (the ostream object).
This way, when formatted input is inserted in the stream, the stream that's returned can immediately be used again (in this case to insert std::endl) simply be appending another method or operator.

I hope that wasn't too confusing. It's called "Method Chaining". I'll post an example in a second.
*EDIT*
1
2
3
4
5
6
7
8
9
10
11
12
13
int main() {

	struct Foo {
		Foo& doThis() { /*this*/return *this; }
		Foo& doThat() {/*that*/return *this; }
	};

	Foo foo;

	foo.doThis().doThat().doThis().doThat();

	return 0;
}
Last edited on
Topic archived. No new replies allowed.