why the return type is istream& ?
we don't use getline like cin input multiple things, I think the return type be void can also work. |
I have to admit that this is a question that I have wondered about.
As you say, it allows you to chain calls like
getline(getline(getline(is, a), b), c); // with strings
and
is.get(a, bufferSize).get(b, bufferSize).get(c, bufferSize); // with char buffers
But note that it's not (simply) the fact that getline, along with other istream and related calls, returns std::istream& (or std::ostream&, etc) that allows you to write code like
1 2 3 4
|
if ( getline( std::cin, someStudent ) )
{
someLecture.addStudent( someStudent );
}
|
That would work, of course, if the return type of getline() was bool.
But getline() returns a reference (std::istream&) to an object. And as you no doubt know, you can't randomly test objects like booleans. For example, if I try the following (with VC++)
1 2 3 4 5 6
|
Random random; // some class without a suitable cast operator
if(random)
{
cout << "true!" << endl;
}
|
I get told to stuff it!
error C2451: conditional expression of type 'Random' is illegal |
The reason it works with istream, etc is that it has an overloaded void* cast operator, and C++ does allow pointers to be tested like booleans.
So the real code, including the cast, is
1 2 3 4
|
if ( (void*)getline( std::cin, someStudent ) )
{
someLecture.addStudent( someStudent );
}
|
and the STL with VC++ 2008 (by P.J. Plauger) defines the void* operator
1 2 3
|
__CLR_OR_THIS_CALL operator void *() const
{ // test if any stream operation has failed
return (fail() ? 0 : (void *)this);
|
(Note this method is defined on ios_base, which is the ultimate base class of all the io streams. And I'm unclear if the void* approach is mandated or if a bool operator could be provided instead.)
So the code is really, under the surface
1 2 3 4
|
if ( !getline( std::cin, someStudent ).fail() )
{
someLecture.addStudent( someStudent );
}
|
So it appears that someone wanted to be able to chain calls and also do boolean style tests and therefore add the void* operator (or similar) so code would behave as they wanted.
Note that the void* cast is provided specifically for use in if(), while(), etc conditions. Casting from a reference to a pointer is something you should avoid like the plague. It's ok to cast between pointer types or between reference types, but you should never use a cast to swap between a pointer and a reference (you use operator* or operator& and then the appropriate cast).
Personally, I'd rather istream didn't support call chaining and that in this situation getline(), etc returned an honest, down to earth bool!
A
nd
y
PS The follow on question, at least for me, is why do so many istream, etc methods need to support call chaining, rather than just those related to extraction (operator>>) and insertion (operator<<)?