why overloading getline return std::istream&

like below,in my book, it's part a Student class function declaraction:
friend std::istream& getline(std::istream& in, Student& stu);

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.

getline(cin, a)getline(cin, b)?
In this case you can test whether the input was successful. For example

1
2
3
4
if ( getline( std::cin, someStudent ) )
{
    someLecture.addStudent( someStudent ); 
}


hi,
vlad from moscow

my question is :
why the return type is istream& ?
why don't just return void ?
my answer is: becuase in case of return type istream & you can check the state of the stream that to know whether there is success or failure of the operation.:)

For example

while ( getline( someFile, someStudent ) ) std::cout << someStudent;

Also you can chain several stream operations if each of them returns reference to the stream.
Last edited on
do you mean use chain like below?
getline(cin, a)getline(cin, b)

It's so weird.
I don't know, because my compiler doesn't accept 'getline()' function.
But I see most likely this code is wrong (compiling error). You should not write two functions in a code line like this.
> I think the return type be void can also work.

Yes, it can work. For instance:
1
2
3
4
5
6
7
8
9
10
Student a ;
getline( std::cin, a ) ;
if( std::cin ) // if there were no errors ie. std::cin is in a good state
{
    // use a ;
}
else
{
    // error in input
}


Returning std::istream& is clearly more convenient:
1
2
3
4
5
6
7
8
9
Student b ;
if( getline( std::cin, b ) )
{
    // use b ;
}
else
{
    // error in input
}


getline is perhaps a poor choice of name for this function, though.
closed account (3qX21hU5)
It is common for functions that read input into vectors, structs, and other container to use a method like this so you can like vlad said check the stream to know if its a success or failure, and also add data to a container or whatever you are doing to that container. Atleast that is what I understand so far from my studies I could be wrong.

For example here is a function that needs to read home work grades for a unknown number of students into a vector that is in a struct.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
istream &read_hw(istream &in, vector<double> &hw)
{
    if (in)
    {
        // Get rid of previous contents
        hw.clear();
        
        double x;
        while (in >> x)
            hw.push_back(x);
        
        // Clear the stream so input for next student will work    
        in.clear();
    }
    return in;
}


And then here is another example of its use that write all the info into the struct.

1
2
3
4
5
6
7
istream &read(istream &is, Student_Info &s)
{
    is >> s.name >> s.midterm >> s.final;
    
    read_hw(is, s.homework);
    return is;
}


All this code came from accelerate C++ which is a great book on C++ and just had it handy from my previous saved exercises.
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!

Andy

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<<)?

Last edited on
In C++11, the 'real code' is:

1
2
if ( static_cast<bool>(getline(std::cin, someStudent)) )
    // ... 


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<<)?


Mostly because it's a far more flexible solution than providing a boolean value that indicates success or failure. It may be you are not terribly concerned with whether the input operation was successful, but you need to loop on eof for some obscure reason. As it is, you're free to use while (!getline(std::cin, someStudent).eof()), while there would be a little contortion required to keep both the input and check in the loop control expression if it only returned a boolean value.
Topic archived. No new replies allowed.